From 571d3f585aa2baa39408ec51e9274940d00e8596 Mon Sep 17 00:00:00 2001 From: Nobuhiro MIKI Date: Fri, 19 Jan 2024 07:29:18 +0000 Subject: [PATCH 001/429] Fix panic in ExtractIntoStructPtr and ExtractIntoSlicePtr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Passing nil as an argument to 'ExtractIntoStructPtr' or 'ExtractIntoSlicePtr' causes "panic: runtime error: invalid memory address or nil pointer dereference". This is an invalid argument and should be corrected to return an error. For reference, standard package functions such as 'json.Unmarshal' return an error instead of panic. Signed-off-by: Nobuhiro MIKI Co-authored-by: pýrus --- results.go | 18 ++++++++++++++++++ testing/results_test.go | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/results.go b/results.go index b3ee9d5682..34ae29b073 100644 --- a/results.go +++ b/results.go @@ -184,10 +184,19 @@ func (r Result) ExtractIntoStructPtr(to interface{}, label string) error { return r.Err } + if to == nil { + return fmt.Errorf("Expected pointer, got %T", to) + } + t := reflect.TypeOf(to) if k := t.Kind(); k != reflect.Ptr { return fmt.Errorf("Expected pointer, got %v", k) } + + if reflect.ValueOf(to).IsNil() { + return fmt.Errorf("Expected pointer, got %T", to) + } + switch t.Elem().Kind() { case reflect.Struct: return r.extractIntoPtr(to, label) @@ -210,10 +219,19 @@ func (r Result) ExtractIntoSlicePtr(to interface{}, label string) error { return r.Err } + if to == nil { + return fmt.Errorf("Expected pointer, got %T", to) + } + t := reflect.TypeOf(to) if k := t.Kind(); k != reflect.Ptr { return fmt.Errorf("Expected pointer, got %v", k) } + + if reflect.ValueOf(to).IsNil() { + return fmt.Errorf("Expected pointer, got %T", to) + } + switch t.Elem().Kind() { case reflect.Slice: return r.extractIntoPtr(to, label) diff --git a/testing/results_test.go b/testing/results_test.go index ddcb1322a4..4905139545 100644 --- a/testing/results_test.go +++ b/testing/results_test.go @@ -113,6 +113,40 @@ func TestUnmarshalAnonymousStructs(t *testing.T) { th.AssertEquals(t, "Canada unmarshalled", actual.Location) } +func TestUnmarshalNilStruct(t *testing.T) { + var x *TestPerson + var y TestPerson + + err1 := gophercloud.Result{}.ExtractIntoStructPtr(&x, "") + err2 := gophercloud.Result{}.ExtractIntoStructPtr(nil, "") + err3 := gophercloud.Result{}.ExtractIntoStructPtr(y, "") + err4 := gophercloud.Result{}.ExtractIntoStructPtr(&y, "") + err5 := gophercloud.Result{}.ExtractIntoStructPtr(x, "") + + th.AssertErr(t, err1) + th.AssertErr(t, err2) + th.AssertErr(t, err3) + th.AssertNoErr(t, err4) + th.AssertErr(t, err5) +} + +func TestUnmarshalNilSlice(t *testing.T) { + var x *[]TestPerson + var y []TestPerson + + err1 := gophercloud.Result{}.ExtractIntoSlicePtr(&x, "") + err2 := gophercloud.Result{}.ExtractIntoSlicePtr(nil, "") + err3 := gophercloud.Result{}.ExtractIntoSlicePtr(y, "") + err4 := gophercloud.Result{}.ExtractIntoSlicePtr(&y, "") + err5 := gophercloud.Result{}.ExtractIntoSlicePtr(x, "") + + th.AssertErr(t, err1) + th.AssertErr(t, err2) + th.AssertErr(t, err3) + th.AssertNoErr(t, err4) + th.AssertErr(t, err5) +} + // TestUnmarshalSliceofAnonymousStructs tests if UnmarshalJSON is called on each // of the anonymous structs contained in an overarching struct slice. func TestUnmarshalSliceOfAnonymousStructs(t *testing.T) { From c0c473618eab0c430c038ebac26adc0933dcdece Mon Sep 17 00:00:00 2001 From: Samuel Allan Date: Wed, 10 Apr 2024 13:52:52 +0930 Subject: [PATCH 002/429] 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 5f4d2492839059f339d594559452ec04c5248830 Mon Sep 17 00:00:00 2001 From: Samuel Allan Date: Thu, 18 Jul 2024 07:35:37 +0930 Subject: [PATCH 003/429] 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() From 755deaf2bef9242399883a77831bf2557e509c71 Mon Sep 17 00:00:00 2001 From: Pierre Prinetti Date: Fri, 5 Jul 2024 16:29:27 +0200 Subject: [PATCH 004/429] MIGRATING.md: Provide a migration script Some steps in the migration from Gophercloud v1 to v2 can be automated. Provide a script that can take out some of the pain. --- docs/MIGRATING.md | 134 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) diff --git a/docs/MIGRATING.md b/docs/MIGRATING.md index a507820bf5..c398cf0e65 100644 --- a/docs/MIGRATING.md +++ b/docs/MIGRATING.md @@ -493,3 +493,137 @@ Users that still rely on theses old services should continue using Gophercloud v (`openstack/networking/v2/extensions/fwaas`) - Poppy (CDNaaS) service (`openstack/cdn`) - Senlin (Clustering) service (`openstack/clustering`) + +### Script-assisted migration + +#### Expected outcome + +After running the script, your code may not compile. The idea is that at this point, you're only left with a few changes that can't reasonably be automated. + +#### What it does + +* Add `/v2` to all Gophercloud imports, except to the packages that have been removed without replacement +* Adjust the import path of moved packages +* Adjust the package identifier in the code where possible +* Add `context.TODO()` where required + +#### Limitations + +* it doesn't fix the use of removed extensions. For example, if you used `openstack/blockstorage/extensions/availabilityzones`, you will have to manually put that back into e.g. `servers.CreateOpts` +* it will just put `context.TODO()` where a context is required to satisfy the function signature. It's up to you to actually replace that with a variable and provide proper cancellation +* it will add `context.TODO()` to `blockstorage/v1` calls, even though that package only exists in Gophercloud v1 + +```bash +# Adjust the blockstorage version appropriately +blockstorageversion=v3 + +openstack='github.com/gophercloud/gophercloud/openstack' +openstack_utils='github.com/gophercloud/utils/openstack' +find . -type f -name '*.go' -exec sed -i ' + /^import ($/,/^)$/ { + + # 1: These packages have been removed and their functionality moved into the main module for the corresponding service. + /\(\/openstack\/blockstorage\/v1\|\/openstack\/networking\/v2\/extensions\/lbaas\|\/openstack\/networking\/v2\/extensions\/lbaas_v2\|\/openstack\/networking\/v2\/extensions\/fwaas\|\/openstack\/cdn\|\/openstack\/clustering\)/! { + /\/openstack\/blockstorage\/extensions\/volumehost/d + /\/openstack\/blockstorage\/extensions\/volumetenants/d + /\/openstack\/compute\/v2\/extensions\/bootfromvolume/d + /\/openstack\/compute\/v2\/extensions\/diskconfig/d + /\/openstack\/compute\/v2\/extensions\/extendedserverattributes/d + /\/openstack\/compute\/v2\/extensions\/extendedstatus/d + /\/openstack\/compute\/v2\/extensions\/schedulerhints/d + /\/openstack\/compute\/v2\/extensions\/serverusage/d + /\/openstack\/compute\/v2\/extensions\/availabilityzones/d + /\/openstack\/identity\/v3\/extensions\/trusts/d + } + + '" + # 2: Functions and supporting structs and interfaces of these packages have been moved to an existing package + s|${openstack}/blockstorage/extensions/schedulerhints|${openstack}/blockstorage/${blockstorageversion}/volumes|g + s|${openstack}/blockstorage/extensions/volumeactions|${openstack}/blockstorage/${blockstorageversion}/volumes|g + s|${openstack}/compute/v2/extensions/evacuate|${openstack}/compute/v2/servers|g + s|${openstack}/compute/v2/extensions/injectnetworkinfo|${openstack}/compute/v2/servers|g + s|${openstack}/compute/v2/extensions/lockunlock|${openstack}/compute/v2/servers|g + s|${openstack}/compute/v2/extensions/migrate|${openstack}/compute/v2/servers|g + s|${openstack}/compute/v2/extensions/pauseunpause|${openstack}/compute/v2/servers|g + s|${openstack}/compute/v2/extensions/rescueunrescue|${openstack}/compute/v2/servers|g + s|${openstack}/compute/v2/extensions/resetnetwork|${openstack}/compute/v2/servers|g + s|${openstack}/compute/v2/extensions/resetstate|${openstack}/compute/v2/servers|g + s|${openstack}/compute/v2/extensions/shelveunshelve|${openstack}/compute/v2/servers|g + s|${openstack}/compute/v2/extensions/startstop|${openstack}/compute/v2/servers|g + s|${openstack}/compute/v2/extensions/suspendresume|${openstack}/compute/v2/servers|g + + # 3: These packages have been renamed + s|${openstack}/imageservice|${openstack}/image|g + s|${openstack_utils}/imageservice|${openstack_utils}/image|g + s|${openstack}/blockstorage/extensions/availabilityzones|${openstack}/blockstorage/${blockstorageversion}/availabilityzones|g + s|${openstack}/blockstorage/extensions/backups|${openstack}/blockstorage/${blockstorageversion}/backups|g + s|${openstack}/blockstorage/extensions/limits|${openstack}/blockstorage/${blockstorageversion}/limits|g + s|${openstack}/blockstorage/extensions/quotasets|${openstack}/blockstorage/${blockstorageversion}/quotasets|g + s|${openstack}/blockstorage/extensions/schedulerstats|${openstack}/blockstorage/${blockstorageversion}/schedulerstats|g + s|${openstack}/blockstorage/extensions/services|${openstack}/blockstorage/${blockstorageversion}/services|g + s|${openstack}/blockstorage/extensions/volumetransfers|${openstack}/blockstorage/${blockstorageversion}/transfers|g + s|${openstack}/compute/v2/extensions/aggregates|${openstack}/compute/v2/aggregates|g + s|${openstack}/compute/v2/extensions/attachinterfaces|${openstack}/compute/v2/attachinterfaces|g + s|${openstack}/compute/v2/extensions/diagnostics|${openstack}/compute/v2/diagnostics|g + s|${openstack}/compute/v2/extensions/hypervisors|${openstack}/compute/v2/hypervisors|g + s|${openstack}/compute/v2/extensions/instanceactions|${openstack}/compute/v2/instanceactions|g + s|${openstack}/compute/v2/extensions/keypairs|${openstack}/compute/v2/keypairs|g + s|${openstack}/compute/v2/extensions/limits|${openstack}/compute/v2/limits|g + s|${openstack}/compute/v2/extensions/quotasets|${openstack}/compute/v2/quotasets|g + s|${openstack}/compute/v2/extensions/remoteconsoles|${openstack}/compute/v2/remoteconsoles|g + s|${openstack}/compute/v2/extensions/secgroups|${openstack}/compute/v2/secgroups|g + s|${openstack}/compute/v2/extensions/servergroups|${openstack}/compute/v2/servergroups|g + s|${openstack}/compute/v2/extensions/services|${openstack}/compute/v2/services|g + s|${openstack}/compute/v2/extensions/tags|${openstack}/compute/v2/tags|g + s|${openstack}/compute/v2/extensions/usage|${openstack}/compute/v2/usage|g + s|${openstack}/compute/v2/extensions/volumeattach|${openstack}/compute/v2/volumeattach|g + s|${openstack}/identity/v2/extensions/admin/roles|${openstack}/identity/v2/roles|g + s|${openstack}/identity/v3/extensions/ec2credentials|${openstack}/identity/v3/ec2credentials|g + s|${openstack}/identity/v3/extensions/ec2tokens|${openstack}/identity/v3/ec2tokens|g + s|${openstack}/identity/v3/extensions/federation|${openstack}/identity/v3/federation|g + s|${openstack}/identity/v3/extensions/oauth1|${openstack}/identity/v3/oauth1|g + s|${openstack}/identity/v3/extensions/projectendpoints|${openstack}/identity/v3/projectendpoints|g + + # 4: These removed packages existed as proxies of others + s|${openstack}/compute/v2/extensions/defsecrules|${openstack}/networking/v2/extensions/security/groups|g + s|${openstack}/compute/v2/extensions/floatingips|${openstack}/networking/v2/extensions/layer3/floatingips|g + s|${openstack}/compute/v2/extensions/images|${openstack}/image/v2/images|g + s|${openstack}/compute/v2/extensions/networks|${openstack}/networking/v2/networks|g + s|${openstack}/compute/v2/extensions/tenantnetworks|${openstack}/networking/v2/networks|g + "' + + # 5: Update to v2, except for packages that were removed without replacement + s|github.com/gophercloud/utils|github.com/gophercloud/utils/v2|g + /\(\/openstack\/blockstorage\/v1\|\/openstack\/networking\/v2\/extensions\/lbaas\|\/openstack\/networking\/v2\/extensions\/lbaas_v2\|\/openstack\/networking\/v2\/extensions\/fwaas\|\/openstack\/cdn\|\/openstack\/clustering\)/! s|github.com/gophercloud/gophercloud|github.com/gophercloud/gophercloud/v2|g + } + + /^)$/,$ { + + # 6: Rename identifiers of items of step 2 above + s#\(schedulerhints\|volumeactions\)\.\([A-Z][A-Z_a-z_0-9]*\)#volumes.\2#g + s#\(evacuate\|injectnetworkinfo\|lockunlock\|migrate\|pauseunpause\|rescueunrescue\|resetnetwork\|resetstate\|shelveunshelve\|startstop\|suspendresume\)\.\([A-Z][A-Z_a-z_0-9]*\)#servers.\2#g + + # 7: Add context.TODO() + s#\(accept\.Create\|accept\.Get\|accounts\.Get\|accounts\.Update\|acls\.DeleteContainerACL\|acls\.DeleteSecretACL\|acls\.GetContainerACL\|acls\.GetSecretACL\|acls\.SetContainerACL\|acls\.SetSecretACL\|acls\.UpdateContainerACL\|acls\.UpdateSecretACL\|addressscopes\.Create\|addressscopes\.Delete\|addressscopes\.Get\|addressscopes\.Update\|agents\.Delete\|agents\.Get\|agents\.ListDHCPNetworks\|agents\.ListL3Routers\|agents\.RemoveBGPSpeaker\|agents\.RemoveDHCPNetwork\|agents\.RemoveL3Router\|agents\.ScheduleBGPSpeaker\|agents\.ScheduleDHCPNetwork\|agents\.ScheduleL3Router\|agents\.Update\|aggregates\.AddHost\|aggregates\.Create\|aggregates\.Delete\|aggregates\.Get\|aggregates\.RemoveHost\|aggregates\.SetMetadata\|aggregates\.Update\|allocations\.Create\|allocations\.Delete\|allocations\.Get\|amphorae\.Failover\|amphorae\.Get\|apiversions\.Get\|apiversions\.List\|applicationcredentials\.Create\|applicationcredentials\.Delete\|applicationcredentials\.DeleteAccessRule\|applicationcredentials\.Get\|applicationcredentials\.GetAccessRule\|attachinterfaces\.Create\|attachinterfaces\.Delete\|attachinterfaces\.Get\|attachments\.Complete\|attachments\.Create\|attachments\.Delete\|attachments\.Get\|attachments\.Update\|attachments\.WaitForStatus\|backups\.Create\|backups\.Delete\|backups\.Export\|backups\.ForceDelete\|backups\.Get\|backups\.Import\|backups\.ResetStatus\|backups\.RestoreFromBackup\|backups\.Update\|bgpvpns\.Create\|bgpvpns\.CreateNetworkAssociation\|bgpvpns\.CreatePortAssociation\|bgpvpns\.CreateRouterAssociation\|bgpvpns\.Delete\|bgpvpns\.DeleteNetworkAssociation\|bgpvpns\.DeletePortAssociation\|bgpvpns\.DeleteRouterAssociation\|bgpvpns\.Get\|bgpvpns\.GetNetworkAssociation\|bgpvpns\.GetPortAssociation\|bgpvpns\.GetRouterAssociation\|bgpvpns\.Update\|bgpvpns\.UpdatePortAssociation\|bgpvpns\.UpdateRouterAssociation\|buildinfo\.Get\|capsules\.Create\|capsules\.Delete\|capsules\.Get\|certificates\.Create\|certificates\.Get\|certificates\.Update\|claims\.Create\|claims\.Delete\|claims\.Get\|claims\.Update\|clusters\.Create\|clusters\.Delete\|clusters\.Get\|clusters\.Resize\|clusters\.Update\|clusters\.Upgrade\|clustertemplates\.Create\|clustertemplates\.Delete\|clustertemplates\.Get\|clustertemplates\.Update\|conductors\.Get\|config\.NewProviderClient\|configurations\.Create\|configurations\.Delete\|configurations\.Get\|configurations\.GetDatastoreParam\|configurations\.GetGlobalParam\|configurations\.Replace\|configurations\.Update\|containers\.BulkDelete\|containers\.Create\|containers\.CreateConsumer\|containers\.CreateSecretRef\|containers\.Delete\|containers\.DeleteConsumer\|containers\.DeleteSecretRef\|containers\.Get\|containers\.Update\|credentials\.Create\|credentials\.Delete\|credentials\.Get\|credentials\.Update\|crontriggers\.Create\|crontriggers\.Delete\|crontriggers\.Get\|databases\.Create\|databases\.Delete\|datastores\.Get\|datastores\.GetVersion\|diagnostics\.Get\|domains\.Create\|domains\.Delete\|domains\.Get\|domains\.Update\|drivers\.GetDriverDetails\|drivers\.GetDriverDiskProperties\|drivers\.GetDriverProperties\|ec2credentials\.Create\|ec2credentials\.Delete\|ec2credentials\.Get\|ec2tokens\.Create\|ec2tokens\.ValidateS3Token\|endpointgroups\.Create\|endpointgroups\.Delete\|endpointgroups\.Get\|endpointgroups\.Update\|endpoints\.Create\|endpoints\.Delete\|endpoints\.Update\|executions\.Create\|executions\.Delete\|executions\.Get\|extensions\.Get\|extraroutes\.Add\|extraroutes\.Remove\|federation\.CreateMapping\|federation\.DeleteMapping\|federation\.GetMapping\|federation\.UpdateMapping\|flavorprofiles\.Create\|flavorprofiles\.Delete\|flavorprofiles\.Get\|flavorprofiles\.Update\|flavors\.AddAccess\|flavors\.Create\|flavors\.CreateExtraSpecs\|flavors\.Delete\|flavors\.DeleteExtraSpec\|flavors\.Get\|flavors\.GetExtraSpec\|flavors\.ListExtraSpecs\|flavors\.RemoveAccess\|flavors\.Update\|flavors\.UpdateExtraSpec\|floatingips\.Create\|floatingips\.Delete\|floatingips\.Get\|floatingips\.Update\|gophercloud\.WaitFor\|groups\.Create\|groups\.Delete\|groups\.Get\|groups\.RemoveEgressPolicy\|groups\.RemoveIngressPolicy\|groups\.Update\|hypervisors\.Get\|hypervisors\.GetStatistics\|hypervisors\.GetUptime\|ikepolicies\.Create\|ikepolicies\.Delete\|ikepolicies\.Get\|ikepolicies\.Update\|imagedata\.Download\|imagedata\.Stage\|imagedata\.Upload\|imageimport\.Create\|imageimport\.Get\|images\.Create\|images\.Delete\|images\.Get\|images\.Update\|instanceactions\.Get\|instances\.AttachConfigurationGroup\|instances\.Create\|instances\.Delete\|instances\.DetachConfigurationGroup\|instances\.EnableRootUser\|instances\.Get\|instances\.IsRootEnabled\|instances\.Resize\|instances\.ResizeVolume\|instances\.Restart\|introspection\.AbortIntrospection\|introspection\.GetIntrospectionData\|introspection\.GetIntrospectionStatus\|introspection\.ReApplyIntrospection\|introspection\.StartIntrospection\|ipsecpolicies\.Create\|ipsecpolicies\.Delete\|ipsecpolicies\.Get\|ipsecpolicies\.Update\|keypairs\.Create\|keypairs\.Delete\|keypairs\.Get\|l7policies\.Create\|l7policies\.CreateRule\|l7policies\.Delete\|l7policies\.DeleteRule\|l7policies\.Get\|l7policies\.GetRule\|l7policies\.Update\|l7policies\.UpdateRule\|limits\.BatchCreate\|limits\.Delete\|limits\.Get\|limits\.GetEnforcementModel\|limits\.Update\|listeners\.Create\|listeners\.Delete\|listeners\.Get\|listeners\.GetStats\|listeners\.Update\|loadbalancers\.Create\|loadbalancers\.Delete\|loadbalancers\.Failover\|loadbalancers\.Get\|loadbalancers\.GetStats\|loadbalancers\.GetStatuses\|loadbalancers\.Update\|members\.Create\|members\.Delete\|members\.Get\|members\.Update\|messages\.Create\|messages\.Delete\|messages\.DeleteMessages\|messages\.Get\|messages\.GetMessages\|messages\.PopMessages\|monitors\.Create\|monitors\.Delete\|monitors\.Get\|monitors\.Update\|networkipavailabilities\.Get\|networks\.Create\|networks\.Delete\|networks\.Get\|networks\.Update\|nodegroups\.Create\|nodegroups\.Delete\|nodegroups\.Get\|nodegroups\.Update\|nodes\.AttachVirtualMedia\|nodes\.ChangePowerState\|nodes\.ChangeProvisionState\|nodes\.Create\|nodes\.CreateSubscription\|nodes\.Delete\|nodes\.DeleteSubscription\|nodes\.DetachVirtualMedia\|nodes\.Get\|nodes\.GetAllSubscriptions\|nodes\.GetBIOSSetting\|nodes\.GetBootDevice\|nodes\.GetInventory\|nodes\.GetSubscription\|nodes\.GetSupportedBootDevices\|nodes\.GetVendorPassthruMethods\|nodes\.InjectNMI\|nodes\.ListBIOSSettings\|nodes\.ListFirmware\|nodes\.SetBootDevice\|nodes\.SetMaintenance\|nodes\.SetRAIDConfig\|nodes\.UnsetMaintenance\|nodes\.Update\|nodes\.Validate\|nodes\.WaitForProvisionState\|oauth1\.AuthorizeToken\|oauth1\.Create\|oauth1\.CreateAccessToken\|oauth1\.CreateConsumer\|oauth1\.DeleteConsumer\|oauth1\.GetAccessToken\|oauth1\.GetAccessTokenRole\|oauth1\.GetConsumer\|oauth1\.RequestToken\|oauth1\.RevokeAccessToken\|oauth1\.UpdateConsumer\|objects\.BulkDelete\|objects\.Copy\|objects\.Create\|objects\.CreateTempURL\|objects\.Delete\|objects\.Download\|objects\.Get\|objects\.Update\|openstack\.Authenticate\|openstack\.AuthenticatedClient\|openstack\.AuthenticateV2\|openstack\.AuthenticateV3\|orders\.Create\|orders\.Delete\|orders\.Get\|osinherit\.Assign\|osinherit\.Unassign\|osinherit\.Validate\|pagination\.Request\|peers\.Create\|peers\.Delete\|peers\.Get\|peers\.Update\|policies\.Create\|policies\.Delete\|policies\.Get\|policies\.InsertRule\|policies\.RemoveRule\|policies\.Update\|pools\.BatchUpdateMembers\|pools\.Create\|pools\.CreateMember\|pools\.Delete\|pools\.DeleteMember\|pools\.Get\|pools\.GetMember\|pools\.Update\|pools\.UpdateMember\|portforwarding\.Create\|portforwarding\.Delete\|portforwarding\.Get\|portforwarding\.Update\|ports\.Create\|ports\.Delete\|ports\.Get\|ports\.Update\|projectendpoints\.Create\|projectendpoints\.Delete\|projects\.Create\|projects\.Delete\|projects\.DeleteTags\|projects\.Get\|projects\.ListTags\|projects\.ModifyTags\|projects\.Update\|qos\.Associate\|qos\.Create\|qos\.Delete\|qos\.DeleteKeys\|qos\.Disassociate\|qos\.DisassociateAll\|qos\.Get\|qos\.Update\|queues\.Create\|queues\.Delete\|queues\.Get\|queues\.GetStats\|queues\.Purge\|queues\.Share\|queues\.Update\|quotas\.Create\|quotasets\.Delete\|quotasets\.Get\|quotasets\.GetDefaults\|quotasets\.GetDetail\|quotasets\.GetUsage\|quotasets\.Update\|quotas\.Get\|quotas\.GetDetail\|quotas\.Update\|rbacpolicies\.Create\|rbacpolicies\.Delete\|rbacpolicies\.Get\|rbacpolicies\.Update\|recordsets\.Create\|recordsets\.Delete\|recordsets\.Get\|recordsets\.Update\|regions\.Create\|regions\.Delete\|regions\.Get\|regions\.Update\|registeredlimits\.BatchCreate\|registeredlimits\.Delete\|registeredlimits\.Get\|registeredlimits\.Update\|remoteconsoles\.Create\|replicas\.Create\|replicas\.Delete\|replicas\.ForceDelete\|replicas\.Get\|replicas\.GetExportLocation\|replicas\.ListExportLocations\|replicas\.Promote\|replicas\.ResetState\|replicas\.ResetStatus\|replicas\.Resync\|request\.Create\|request\.Delete\|request\.Get\|request\.Update\|resourceproviders\.Create\|resourceproviders\.Delete\|resourceproviders\.Get\|resourceproviders\.GetAllocations\|resourceproviders\.GetInventories\|resourceproviders\.GetTraits\|resourceproviders\.GetUsages\|resourceproviders\.Update\|resourcetypes\.GenerateTemplate\|resourcetypes\.GetSchema\|resourcetypes\.List\|roles\.AddUser\|roles\.Assign\|roles\.Create\|roles\.CreateRoleInferenceRule\|roles\.Delete\|roles\.DeleteRoleInferenceRule\|roles\.DeleteUser\|roles\.Get\|roles\.GetRoleInferenceRule\|roles\.ListRoleInferenceRules\|roles\.Unassign\|roles\.Update\|routers\.AddInterface\|routers\.Create\|routers\.Delete\|routers\.Get\|routers\.RemoveInterface\|routers\.Update\|rules\.Create\|rules\.CreateBandwidthLimitRule\|rules\.CreateDSCPMarkingRule\|rules\.CreateMinimumBandwidthRule\|rules\.Delete\|rules\.DeleteBandwidthLimitRule\|rules\.DeleteDSCPMarkingRule\|rules\.DeleteMinimumBandwidthRule\|rules\.Get\|rules\.GetBandwidthLimitRule\|rules\.GetDSCPMarkingRule\|rules\.GetMinimumBandwidthRule\|rules\.Update\|rules\.UpdateBandwidthLimitRule\|rules\.UpdateDSCPMarkingRule\|rules\.UpdateMinimumBandwidthRule\|ruletypes\.GetRuleType\|secgroups\.AddServer\|secgroups\.Create\|secgroups\.CreateRule\|secgroups\.Delete\|secgroups\.DeleteRule\|secgroups\.Get\|secgroups\.RemoveServer\|secgroups\.Update\|secrets\.Create\|secrets\.CreateMetadata\|secrets\.CreateMetadatum\|secrets\.Delete\|secrets\.DeleteMetadatum\|secrets\.Get\|secrets\.GetMetadata\|secrets\.GetMetadatum\|secrets\.GetPayload\|secrets\.Update\|secrets\.UpdateMetadatum\|securityservices\.Create\|securityservices\.Delete\|securityservices\.Get\|securityservices\.Update\|servergroups\.Create\|servergroups\.Delete\|servergroups\.Get\|servers\.ChangeAdminPassword\|servers\.ConfirmResize\|servers\.Create\|servers\.CreateImage\|servers\.CreateMetadatum\|servers\.Delete\|servers\.DeleteMetadatum\|servers\.Evacuate\|servers\.ForceDelete\|servers\.Get\|servers\.GetPassword\|servers\.InjectNetworkInfo\|servers\.LiveMigrate\|servers\.Lock\|servers\.Metadata\|servers\.Metadatum\|servers\.Migrate\|servers\.Pause\|servers\.Reboot\|servers\.Rebuild\|servers\.Rescue\|servers\.ResetMetadata\|servers\.ResetNetwork\|servers\.ResetState\|servers\.Resize\|servers\.Resume\|servers\.RevertResize\|servers\.Shelve\|servers\.ShelveOffload\|servers\.ShowConsoleOutput\|servers\.Start\|servers\.Stop\|servers\.Suspend\|servers\.Unlock\|servers\.Unpause\|servers\.Unrescue\|servers\.Unshelve\|servers\.Update\|servers\.UpdateMetadata\|servers\.WaitForStatus\|services\.Create\|services\.Delete\|services\.Get\|services\.Update\|shareaccessrules\.Get\|shareaccessrules\.List\|sharenetworks\.AddSecurityService\|sharenetworks\.Create\|sharenetworks\.Delete\|sharenetworks\.Get\|sharenetworks\.RemoveSecurityService\|sharenetworks\.Update\|shares\.Create\|shares\.Delete\|shares\.DeleteMetadatum\|shares\.Extend\|shares\.ForceDelete\|shares\.Get\|shares\.GetExportLocation\|shares\.GetMetadata\|shares\.GetMetadatum\|shares\.GrantAccess\|shares\.ListAccessRights\|shares\.ListExportLocations\|shares\.ResetStatus\|shares\.Revert\|shares\.RevokeAccess\|shares\.SetMetadata\|shares\.Shrink\|shares\.Unmanage\|shares\.Update\|shares\.UpdateMetadata\|sharetransfers\.Accept\|sharetransfers\.Create\|sharetransfers\.Delete\|sharetransfers\.Get\|sharetypes\.AddAccess\|sharetypes\.Create\|sharetypes\.Delete\|sharetypes\.GetDefault\|sharetypes\.GetExtraSpecs\|sharetypes\.RemoveAccess\|sharetypes\.SetExtraSpecs\|sharetypes\.ShowAccess\|sharetypes\.UnsetExtraSpecs\|siteconnections\.Create\|siteconnections\.Delete\|siteconnections\.Get\|siteconnections\.Update\|snapshots\.Create\|snapshots\.Delete\|snapshots\.ForceDelete\|snapshots\.Get\|snapshots\.ResetStatus\|snapshots\.Update\|snapshots\.UpdateMetadata\|snapshots\.UpdateStatus\|snapshots\.WaitForStatus\|speakers\.AddBGPPeer\|speakers\.AddGatewayNetwork\|speakers\.Create\|speakers\.Delete\|speakers\.Get\|speakers\.RemoveBGPPeer\|speakers\.RemoveGatewayNetwork\|speakers\.Update\|stackevents\.Find\|stackevents\.Get\|stackresources\.Find\|stackresources\.Get\|stackresources\.MarkUnhealthy\|stackresources\.Metadata\|stackresources\.Schema\|stackresources\.Template\|stacks\.Abandon\|stacks\.Adopt\|stacks\.Create\|stacks\.Delete\|stacks\.Find\|stacks\.Get\|stacks\.Preview\|stacks\.Update\|stacks\.UpdatePatch\|stacktemplates\.Get\|stacktemplates\.Validate\|subnetpools\.Create\|subnetpools\.Delete\|subnetpools\.Get\|subnetpools\.Update\|subnets\.Create\|subnets\.Delete\|subnets\.Get\|subnets\.Update\|swauth\.Auth\|swauth\.NewObjectStorageV1\|tags\.Add\|tags\.Check\|tags\.Delete\|tags\.DeleteAll\|tags\.List\|tags\.ReplaceAll\|tasks\.Create\|tasks\.Get\|tenants\.Create\|tenants\.Delete\|tenants\.Get\|tenants\.Update\|tokens\.Create\|tokens\.Get\|tokens\.Revoke\|tokens\.Validate\|transfers\.Accept\|transfers\.Create\|transfers\.Delete\|transfers\.Get\|trunks\.AddSubports\|trunks\.Create\|trunks\.Delete\|trunks\.Get\|trunks\.GetSubports\|trunks\.RemoveSubports\|trunks\.Update\|trusts\.CheckRole\|trusts\.Create\|trusts\.Delete\|trusts\.Get\|trusts\.GetRole\|users\.AddToGroup\|users\.ChangePassword\|users\.Create\|users\.Delete\|users\.Get\|users\.IsMemberOfGroup\|users\.RemoveFromGroup\|users\.Update\|utils\.ChooseVersion\|utils\.GetSupportedMicroversions\|utils\.RequireMicroversion\|volumeattach\.Create\|volumeattach\.Delete\|volumeattach\.Get\|volumes\.Attach\|volumes\.BeginDetaching\|volumes\.ChangeType\|volumes\.Create\|volumes\.Delete\|volumes\.Detach\|volumes\.ExtendSize\|volumes\.ForceDelete\|volumes\.Get\|volumes\.InitializeConnection\|volumes\.ReImage\|volumes\.Reserve\|volumes\.ResetStatus\|volumes\.SetBootable\|volumes\.SetImageMetadata\|volumes\.TerminateConnection\|volumes\.Unreserve\|volumes\.Update\|volumes\.UploadImage\|volumes\.WaitForStatus\|volumetypes\.AddAccess\|volumetypes\.Create\|volumetypes\.CreateEncryption\|volumetypes\.CreateExtraSpecs\|volumetypes\.Delete\|volumetypes\.DeleteEncryption\|volumetypes\.DeleteExtraSpec\|volumetypes\.Get\|volumetypes\.GetEncryption\|volumetypes\.GetEncryptionSpec\|volumetypes\.GetExtraSpec\|volumetypes\.ListExtraSpecs\|volumetypes\.RemoveAccess\|volumetypes\.Update\|volumetypes\.UpdateEncryption\|volumetypes\.UpdateExtraSpec\|workflows\.Create\|workflows\.Delete\|workflows\.Get\|zones\.Create\|zones\.Delete\|zones\.Get\|zones\.Update\)(#\1(context.TODO(), #g + s#\(\.AllPages(\)#\1context.TODO(), #g + s#\(\.EachPage(\)\(func(\)#\1context.TODO(), \2ctx context.Context, #g + + # 8: Rename identifiers that were changed in v2 + s#\(\(volumes\|servers\)\.SchedulerHint\)s#\2.SchedulerHintOpts#g + + # 9: Tentatively replace error handling for 404s + s#\(\t\+\)if _, ok := err.(gophercloud.ErrDefault404); \(!\?\)ok {#\1if \2gophercloud.ResponseCodeIs(err, http.StatusNotFound) {#g + } + ' {} \; + +grep -r -l 'context\.TODO' | xargs -r sed -i ' + /^import ($/ a "context" + ' + +grep -r -l 'http\.Status' | xargs -r sed -i ' + /^import ($/ a "net/http" + ' + +goimports -format-only -w . +go mod tidy +``` From 1856c8a781936d22e7036d1e41e0097776260c6e Mon Sep 17 00:00:00 2001 From: Pierre Prinetti Date: Thu, 18 Jul 2024 10:34:03 +0200 Subject: [PATCH 005/429] actions: Correctly refresh hold state Before adding these trigger types, the `hold` job was often skipped, unnecessarily blocking the Pull request. --- .github/workflows/check-pr-labels.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/check-pr-labels.yaml b/.github/workflows/check-pr-labels.yaml index ea8068f602..4fbb7fc0b8 100644 --- a/.github/workflows/check-pr-labels.yaml +++ b/.github/workflows/check-pr-labels.yaml @@ -2,8 +2,11 @@ name: Ready on: pull_request_target: types: - - opened - labeled + - opened + - reopened + - synchronize + - unlabeled jobs: hold: From 3b8dd05aca27f4609e4a7ba4a5cf49c15248c68c Mon Sep 17 00:00:00 2001 From: Pierre Prinetti Date: Thu, 18 Jul 2024 15:05:33 +0200 Subject: [PATCH 006/429] actions: Refactor the semver assessment Using `gh` lets us drop two external dependencies, and condensate the steps a bit. After this change: * new pushes in the PR won't trigger relabeling if the assessment is unchanged * failures in the workflow will be notified as comments in the PR rather than via the `semver:unknown` label The next natural step is to set this job as mandatory, to that a failure to assess semver will block merging. --- .github/labels.yaml | 3 -- .github/workflows/semver-auto.yaml | 71 ++++++++++++++++-------------- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/.github/labels.yaml b/.github/labels.yaml index 479fb5f3a7..3069b5bd6b 100644 --- a/.github/labels.yaml +++ b/.github/labels.yaml @@ -22,9 +22,6 @@ - color: '6E7624' description: No API change name: semver:patch -- color: 'EC0101' - description: Unable to figure out the semver type - name: semver:unknown - color: 'D73A4A' description: Do not merge name: hold diff --git a/.github/workflows/semver-auto.yaml b/.github/workflows/semver-auto.yaml index c042be134a..eb92701452 100644 --- a/.github/workflows/semver-auto.yaml +++ b/.github/workflows/semver-auto.yaml @@ -1,21 +1,15 @@ -name: Add PR semver labels +name: Add semver labels on: pull_request_target: - types: [opened, synchronize, reopened] + types: + - opened + - synchronize + - reopened + jobs: go-apidiff: runs-on: ubuntu-latest steps: - - name: Remove the semver labels - uses: actions-ecosystem/action-remove-labels@2ce5d41b4b6aa8503e285553f75ed56e0a40bae0 - with: - labels: | - semver:patch - semver:minor - semver:major - semver:unknown - github_token: ${{ secrets.GITHUB_TOKEN }} - - uses: actions/checkout@v4 with: fetch-depth: 0 @@ -30,13 +24,6 @@ jobs: env: GIT_SEQUENCE_EDITOR: '/usr/bin/true' - - name: Add semver:unknown label - if: failure() - uses: actions-ecosystem/action-add-labels@18f1af5e3544586314bbe15c0273249c770b2daf - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - labels: semver:unknown - - uses: actions/setup-go@v5 with: go-version: '1' @@ -54,23 +41,39 @@ jobs: if: steps.go-apidiff.outcome != 'success' && steps.go-apidiff.outputs.semver-type != 'major' run: exit 1 - - name: Add semver:patch label + - name: Add label semver:patch if: steps.go-apidiff.outputs.semver-type == 'patch' - uses: actions-ecosystem/action-add-labels@18f1af5e3544586314bbe15c0273249c770b2daf - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - labels: semver:patch + run: gh pr edit "$NUMBER" --add-label "semver:patch" --remove-label "semver:major,semver:minor" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} + NUMBER: ${{ github.event.pull_request.number }} - - name: Add semver:minor label + - name: Add label semver:minor if: steps.go-apidiff.outputs.semver-type == 'minor' - uses: actions-ecosystem/action-add-labels@18f1af5e3544586314bbe15c0273249c770b2daf - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - labels: semver:minor + run: gh pr edit "$NUMBER" --add-label "semver:minor" --remove-label "semver:major,semver:patch" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} + NUMBER: ${{ github.event.pull_request.number }} - - name: Add semver:major label + - name: Add label semver:major if: steps.go-apidiff.outputs.semver-type == 'major' - uses: actions-ecosystem/action-add-labels@18f1af5e3544586314bbe15c0273249c770b2daf - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - labels: semver:major + run: gh pr edit "$NUMBER" --add-label "semver:major" --remove-label "semver:minor,semver:patch" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} + NUMBER: ${{ github.event.pull_request.number }} + + - name: Report failure + if: failure() + run: | + gh pr edit "$NUMBER" --remove-label "semver:major,semver:minor,semver:patch" + gh issue comment "$NUMBER" --body "$BODY" + exit 1 + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} + NUMBER: ${{ github.event.pull_request.number }} + BODY: > + Failed to assess the semver bump. See [logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details. From 364b4bcaf3321a512e92b1bd4145d300a82b870b Mon Sep 17 00:00:00 2001 From: Przemyslaw Szczerbik Date: Tue, 16 Jul 2024 00:36:22 -0700 Subject: [PATCH 007/429] Align ServiceFail provisioning state value with Ironic There is a mismatch between ServiceFail values used by Gophercloud and Ironic. Ironic uses "service failed" value [1], rather than "service fail". This commit addresses this discrepancy. [1] https://github.com/openstack/ironic/blob/stable/2024.1/ironic/common/states.py#L248 Signed-off-by: Przemyslaw Szczerbik --- openstack/baremetal/v1/nodes/requests.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openstack/baremetal/v1/nodes/requests.go b/openstack/baremetal/v1/nodes/requests.go index f79721b4e7..8cb0de9e05 100644 --- a/openstack/baremetal/v1/nodes/requests.go +++ b/openstack/baremetal/v1/nodes/requests.go @@ -50,7 +50,7 @@ const ( Unrescuing ProvisionState = "unrescuing" Servicing ProvisionState = "servicing" ServiceWait ProvisionState = "service wait" - ServiceFail ProvisionState = "service fail" + ServiceFail ProvisionState = "service failed" ServiceHold ProvisionState = "service hold" ) From 6815cc5264b642ef7cc7a1083be430837cb6aec7 Mon Sep 17 00:00:00 2001 From: Sharpz7 Date: Fri, 19 Jul 2024 11:43:51 +0000 Subject: [PATCH 008/429] Added node.Retired --- openstack/baremetal/v1/nodes/results.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/openstack/baremetal/v1/nodes/results.go b/openstack/baremetal/v1/nodes/results.go index 0602add768..5c6eb5c190 100644 --- a/openstack/baremetal/v1/nodes/results.go +++ b/openstack/baremetal/v1/nodes/results.go @@ -261,6 +261,13 @@ type Node struct { // The UTC date and time when the last inspection was finished, ISO 8601 format. May be “null” if inspection hasn't been finished yet. InspectionFinishedAt *time.Time `json:"inspection_finished_at"` + + // Whether the node is retired. A Node tagged as retired will prevent any further + // scheduling of instances, but will still allow for other operations, such as cleaning, to happen + Retired bool `json:"retired"` + + // Reason the node is marked as retired. + RetiredReason string `json:"retired_reason"` } // NodePage abstracts the raw results of making a List() request against From 505e8cd50fe77e0b1b18912e0ae4d6515049c957 Mon Sep 17 00:00:00 2001 From: Sharpz7 Date: Fri, 19 Jul 2024 14:51:12 +0000 Subject: [PATCH 009/429] Added tests --- .../v1/nodes/testing/fixtures_test.go | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/openstack/baremetal/v1/nodes/testing/fixtures_test.go b/openstack/baremetal/v1/nodes/testing/fixtures_test.go index 8ab570b54d..d47d70b13c 100644 --- a/openstack/baremetal/v1/nodes/testing/fixtures_test.go +++ b/openstack/baremetal/v1/nodes/testing/fixtures_test.go @@ -149,6 +149,8 @@ const NodeListDetailBody = ` "provision_updated_at": "2019-02-15T17:21:29+00:00", "raid_config": {}, "raid_interface": "no-raid", + "retired": false, + "retired_reason": "No longer needed", "rescue_interface": "no-rescue", "reservation": null, "resource_class": null, @@ -247,6 +249,8 @@ const NodeListDetailBody = ` "provision_updated_at": null, "raid_config": {}, "raid_interface": "no-raid", + "retired": false, + "retired_reason": "No longer needed", "rescue_interface": "no-rescue", "reservation": null, "resource_class": null, @@ -345,6 +349,8 @@ const NodeListDetailBody = ` "provision_updated_at": null, "raid_config": {}, "raid_interface": "no-raid", + "retired": false, + "retired_reason": "No longer needed", "rescue_interface": "no-rescue", "reservation": null, "resource_class": null, @@ -456,6 +462,8 @@ const SingleNodeBody = ` "provision_updated_at": "2019-02-15T17:21:29+00:00", "raid_config": {}, "raid_interface": "no-raid", + "retired": false, + "retired_reason": "No longer needed", "rescue_interface": "no-rescue", "reservation": null, "resource_class": null, @@ -855,7 +863,7 @@ const NodeFirmwareListBody = ` { "firmware": [ { - "created_at": "2023-10-03T18:30:00+00:00", + "created_at": "2023-10-03T18:30:00+00:00", "updated_at": null, "component": "bios", "initial_version": "U30 v2.36 (07/16/2020)", @@ -864,10 +872,10 @@ const NodeFirmwareListBody = ` }, { "created_at": "2023-10-03T18:30:00+00:00", - "updated_at": "2023-10-03T18:45:54+00:00", - "component": "bmc", - "initial_version": "iLO 5 v2.78", - "current_version": "iLO 5 v2.81", + "updated_at": "2023-10-03T18:45:54+00:00", + "component": "bmc", + "initial_version": "iLO 5 v2.78", + "current_version": "iLO 5 v2.81", "last_version_flashed": "iLO 5 v2.81" } ] @@ -949,6 +957,8 @@ var ( CreatedAt: createdAtFoo, UpdatedAt: updatedAt, ProvisionUpdatedAt: provisonUpdatedAt, + Retired: false, + RetiredReason: "No longer needed", } NodeFooValidation = nodes.NodeValidation{ @@ -1058,6 +1068,8 @@ var ( UpdatedAt: updatedAt, InspectionStartedAt: &InspectionStartedAt, InspectionFinishedAt: &InspectionFinishedAt, + Retired: false, + RetiredReason: "No longer needed", } NodeBaz = nodes.Node{ @@ -1105,6 +1117,8 @@ var ( ProtectedReason: "", CreatedAt: createdAtBaz, UpdatedAt: updatedAt, + Retired: false, + RetiredReason: "No longer needed", } ConfigDriveMap = nodes.ConfigDrive{ From e5197df8061baf5812d2239d09696f9a28d0b6df Mon Sep 17 00:00:00 2001 From: Pierre Prinetti Date: Mon, 22 Jul 2024 10:15:35 +0200 Subject: [PATCH 010/429] Add needinfo label Includes a Github action that automatically removes the `needinfo` label when the original author adds a comment. --- .github/labels.yaml | 3 +++ .github/workflows/label-issue.yaml | 17 +++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 .github/workflows/label-issue.yaml diff --git a/.github/labels.yaml b/.github/labels.yaml index 3069b5bd6b..a266cf1678 100644 --- a/.github/labels.yaml +++ b/.github/labels.yaml @@ -25,3 +25,6 @@ - color: 'D73A4A' description: Do not merge name: hold +- color: 'F9D0C4' + description: Additional information requested + name: needinfo diff --git a/.github/workflows/label-issue.yaml b/.github/workflows/label-issue.yaml new file mode 100644 index 0000000000..723f4cd04e --- /dev/null +++ b/.github/workflows/label-issue.yaml @@ -0,0 +1,17 @@ +name: Label issue +on: + issue_comment: + types: + - created + +jobs: + clear_needinfo: + name: Clear needinfo + if: ${{ github.event.issue.user.login }} == ${{ github.event.comment.user.login }} + runs-on: ubuntu-latest + steps: + - run: gh pr edit "$NUMBER" --remove-label "needinfo" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} + NUMBER: ${{ github.event.pull_request.number }} From a4a2239bb7bb15ea1e9ffa5fce55e15a405956ce Mon Sep 17 00:00:00 2001 From: Pierre Prinetti Date: Fri, 19 Jul 2024 12:07:37 +0200 Subject: [PATCH 011/429] actions: Label PRs based on the paths of files being changed To facilitate PR assignment and ultimately reviews, label the PRs based on what they touch. --- .github/labeler.yml | 144 ++++++++++++++++++ .github/labels.yaml | 95 +++++++++++- .../{semver-auto.yaml => label-pr.yaml} | 12 +- 3 files changed, 243 insertions(+), 8 deletions(-) create mode 100644 .github/labeler.yml rename .github/workflows/{semver-auto.yaml => label-pr.yaml} (94%) diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000000..a07b39fe3e --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,144 @@ +edit:dependencies: +- changed-files: + - any-glob-to-any-file: + - 'go.mod' + - 'go.sum' + - '.github/dependabot.yml' +edit:actions: +- changed-files: + - any-glob-to-any-file: + - '.github/**' +edit:gophercloud: +- changed-files: + - any-glob-to-any-file: + - '*.go' + - 'testing/**' + - 'pagination/**' +edit:openstack: +- changed-files: + - any-glob-to-any-file: + - 'openstack/*' + - 'openstack/testing/**' +edit:baremetal: +- changed-files: + - any-glob-to-any-file: + - 'openstack/baremetal/**' + - 'internal/acceptance/openstack/baremetal/**' +edit:baremetalintrospection: +- changed-files: + - any-glob-to-any-file: + - 'openstack/baremetalintrospection/**' +edit:blockstorage: +- changed-files: + - any-glob-to-any-file: + - 'openstack/blockstorage/**' + - 'internal/acceptance/openstack/blockstorage/**' +edit:common: +- changed-files: + - any-glob-to-any-file: + - 'openstack/common/**' +edit:compute: +- changed-files: + - any-glob-to-any-file: + - 'openstack/compute/**' + - 'internal/acceptance/openstack/compute/**' +edit:config: +- changed-files: + - any-glob-to-any-file: + - 'openstack/config/**' +edit:container: +- changed-files: + - any-glob-to-any-file: + - 'openstack/container/**' + - 'internal/acceptance/openstack/container/**' +edit:containerinfra: +- changed-files: + - any-glob-to-any-file: + - 'openstack/containerinfra/**' + - 'internal/acceptance/openstack/containerinfra/**' +edit:db: +- changed-files: + - any-glob-to-any-file: + - 'openstack/db/**' + - 'internal/acceptance/openstack/db/**' +edit:dns: +- changed-files: + - any-glob-to-any-file: + - 'openstack/dns/**' + - 'internal/acceptance/openstack/dns/**' +edit:identity: +- changed-files: + - any-glob-to-any-file: + - 'openstack/identity/**' + - 'internal/acceptance/openstack/identity/**' +edit:image: +- changed-files: + - any-glob-to-any-file: + - 'openstack/image/**' + - 'internal/acceptance/openstack/image/**' +edit:keymanager: +- changed-files: + - any-glob-to-any-file: + - 'openstack/keymanager/**' + - 'internal/acceptance/openstack/keymanager/**' +edit:loadbalancer: +- changed-files: + - any-glob-to-any-file: + - 'openstack/loadbalancer/**' + - 'internal/acceptance/openstack/loadbalancer/**' +edit:messaging: +- changed-files: + - any-glob-to-any-file: + - 'openstack/messaging/**' + - 'internal/acceptance/openstack/messaging/**' +edit:networking: +- changed-files: + - any-glob-to-any-file: + - 'openstack/networking/**' + - 'internal/acceptance/openstack/networking/**' +edit:objectstorage: +- changed-files: + - any-glob-to-any-file: + - 'openstack/objectstorage/**' + - 'internal/acceptance/openstack/objectstorage/**' +edit:orchestration: +- changed-files: + - any-glob-to-any-file: + - 'openstack/orchestration/**' + - 'internal/acceptance/openstack/orchestration/**' +edit:placement: +- changed-files: + - any-glob-to-any-file: + - 'openstack/placement/**' + - 'internal/acceptance/openstack/placement/**' +edit:sharedfilesystems: +- changed-files: + - any-glob-to-any-file: + - 'openstack/sharedfilesystems/**' + - 'internal/acceptance/openstack/sharedfilesystems/**' +edit:testinfra: +- changed-files: + - any-glob-to-any-file: + - 'testhelper/**' + - 'internal/acceptance/*' + - 'internal/acceptance/openstack/*' + - 'internal/acceptance/clients/**' + - 'internal/acceptance/tools/**' + - '.github/workflows/functional-*.yaml' + - '.github/workflows/unit.yaml' + - '.github/workflows/lint.yaml' + - 'script/**' +edit:utils: +- changed-files: + - any-glob-to-any-file: + - 'openstack/utils/**' +edit:workflow: +- changed-files: + - any-glob-to-any-file: + - 'openstack/workflow/**' + - 'internal/acceptance/openstack/workflow/**' + +v1: +- base-branch: 'v1' +v2: +- base-branch: 'v2' diff --git a/.github/labels.yaml b/.github/labels.yaml index a266cf1678..4f888b4d4f 100644 --- a/.github/labels.yaml +++ b/.github/labels.yaml @@ -4,12 +4,6 @@ - color: 'E99695' description: This PR will be backported to v2 name: backport-v2 -- color: '0366d6' - description: Pull requests that update a dependency file - name: dependencies -- color: '000000' - description: Pull requests that update GitHub Actions code - name: github_actions - color: 'BCF611' description: A good issue for first-time contributors name: good first issue @@ -28,3 +22,92 @@ - color: 'F9D0C4' description: Additional information requested name: needinfo + +- color: '30ABB9' + description: This PR targets v1 + name: v1 +- color: 'E99695' + description: This PR targets v2 + name: v2 + +- color: '000000' + description: This PR updates dependencies + name: edit:dependencies +- color: '000000' + description: This PR updates GitHub Actions code + name: edit:actions +- color: '000000' + description: This PR updates common Gophercloud code + name: edit:gophercloud +- color: '000000' + description: This PR updates common OpenStack code + name: edit:openstack +- color: '000000' + description: This PR updates baremetal code + name: edit:baremetal +- color: '000000' + description: This PR updates baremetalintrospection code + name: edit:baremetalintrospection +- color: '000000' + description: This PR updates blockstorage code + name: edit:blockstorage +- color: '000000' + description: This PR updates common code + name: edit:common +- color: '000000' + description: This PR updates compute code + name: edit:compute +- color: '000000' + description: This PR updates config code + name: edit:config +- color: '000000' + description: This PR updates container code + name: edit:container +- color: '000000' + description: This PR updates containerinfra code + name: edit:containerinfra +- color: '000000' + description: This PR updates db code + name: edit:db +- color: '000000' + description: This PR updates dns code + name: edit:dns +- color: '000000' + description: This PR updates identity code + name: edit:identity +- color: '000000' + description: This PR updates image code + name: edit:image +- color: '000000' + description: This PR updates keymanager code + name: edit:keymanager +- color: '000000' + description: This PR updates loadbalancer code + name: edit:loadbalancer +- color: '000000' + description: This PR updates messaging code + name: edit:messaging +- color: '000000' + description: This PR updates networking code + name: edit:networking +- color: '000000' + description: This PR updates objectstorage code + name: edit:objectstorage +- color: '000000' + description: This PR updates orchestration code + name: edit:orchestration +- color: '000000' + description: This PR updates placement code + name: edit:placement +- color: '000000' + description: This PR updates sharedfilesystems code + name: edit:sharedfilesystems +- color: '000000' + description: This PR updates testing code + name: edit:testing +- color: '000000' + description: This PR updates utils code + name: edit:utils +- color: '000000' + description: This PR updates workflow code + name: edit:workflow diff --git a/.github/workflows/semver-auto.yaml b/.github/workflows/label-pr.yaml similarity index 94% rename from .github/workflows/semver-auto.yaml rename to .github/workflows/label-pr.yaml index eb92701452..44d46b0e15 100644 --- a/.github/workflows/semver-auto.yaml +++ b/.github/workflows/label-pr.yaml @@ -1,4 +1,4 @@ -name: Add semver labels +name: Label PR on: pull_request_target: types: @@ -7,7 +7,7 @@ on: - reopened jobs: - go-apidiff: + semver: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -77,3 +77,11 @@ jobs: NUMBER: ${{ github.event.pull_request.number }} BODY: > Failed to assess the semver bump. See [logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details. + + edits: + permissions: + contents: read + pull-requests: write + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@v5 From 059261336036fc3121fd60ebefafe7a3159f5352 Mon Sep 17 00:00:00 2001 From: Pierre Prinetti Date: Mon, 22 Jul 2024 15:57:00 +0200 Subject: [PATCH 012/429] Github templates: Hide suggestions Use HTML comments to hide the suggestions from the final issue or Pull request text. --- .github/ISSUE_TEMPLATE | 2 ++ .github/PULL_REQUEST_TEMPLATE | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.github/ISSUE_TEMPLATE b/.github/ISSUE_TEMPLATE index 2c3be773ad..da9c8472d6 100644 --- a/.github/ISSUE_TEMPLATE +++ b/.github/ISSUE_TEMPLATE @@ -1 +1,3 @@ + diff --git a/.github/PULL_REQUEST_TEMPLATE b/.github/PULL_REQUEST_TEMPLATE index 6978cc2c53..fb271a3334 100644 --- a/.github/PULL_REQUEST_TEMPLATE +++ b/.github/PULL_REQUEST_TEMPLATE @@ -1,9 +1,11 @@ + Fixes #[PUT ISSUE NUMBER HERE] Links to the line numbers/files in the OpenStack source code that support the From ff438b14e97707ca5ea514455c3cd08cfe57a5ce Mon Sep 17 00:00:00 2001 From: Pierre Prinetti Date: Tue, 23 Jul 2024 14:57:53 +0200 Subject: [PATCH 013/429] Prepare v2.1.0 --- CHANGELOG.md | 10 ++++++++++ provider_client.go | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d7dfbc469..4e4d1c854e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +## v2.1.0 + +* [GH-3078](https://github.com/gophercloud/gophercloud/pull/3078) [networking]: add BGP VPNs support +* [GH-3086](https://github.com/gophercloud/gophercloud/pull/3086) build(deps): bump golang.org/x/crypto from 0.24.0 to 0.25.0 +* [GH-3090](https://github.com/gophercloud/gophercloud/pull/3090) Adding support for field dns_publish_fixed_ip in a subnet +* [GH-3092](https://github.com/gophercloud/gophercloud/pull/3092) [neutron]: introduce Stateful argument for the security groups +* [GH-3094](https://github.com/gophercloud/gophercloud/pull/3094) [neutron]: introduce Description argument for the portforwarding +* [GH-3106](https://github.com/gophercloud/gophercloud/pull/3106) clouds: Parse trust_id from clouds.yaml +* [GH-3131](https://github.com/gophercloud/gophercloud/pull/3131) Align ServiceFail provisioning state value with Ironic + ## v2.0.0 (2024-05-27) MAIN BREAKING CHANGES: diff --git a/provider_client.go b/provider_client.go index f8c4928cbd..a4a8dce51d 100644 --- a/provider_client.go +++ b/provider_client.go @@ -13,7 +13,7 @@ import ( // DefaultUserAgent is the default User-Agent string set in the request header. const ( - DefaultUserAgent = "gophercloud/v2.0.0" + DefaultUserAgent = "gophercloud/v2.1.0" DefaultMaxBackoffRetries = 60 ) From a9b9111de59a4b70c93a69b2fecf5a2c02b29f54 Mon Sep 17 00:00:00 2001 From: Pierre Prinetti Date: Tue, 23 Jul 2024 14:57:53 +0200 Subject: [PATCH 014/429] Prepare v2.1.0 --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e4d1c854e..bae5109cfe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## v2.1.0 +## v2.1.0 (2024-07-24) * [GH-3078](https://github.com/gophercloud/gophercloud/pull/3078) [networking]: add BGP VPNs support * [GH-3086](https://github.com/gophercloud/gophercloud/pull/3086) build(deps): bump golang.org/x/crypto from 0.24.0 to 0.25.0 @@ -7,6 +7,7 @@ * [GH-3094](https://github.com/gophercloud/gophercloud/pull/3094) [neutron]: introduce Description argument for the portforwarding * [GH-3106](https://github.com/gophercloud/gophercloud/pull/3106) clouds: Parse trust_id from clouds.yaml * [GH-3131](https://github.com/gophercloud/gophercloud/pull/3131) Align ServiceFail provisioning state value with Ironic +* [GH-3136](https://github.com/gophercloud/gophercloud/pull/3136) Added node.Retired ## v2.0.0 (2024-05-27) From dd7130d65994f874114fcb2efe94a544b244531e Mon Sep 17 00:00:00 2001 From: Pierre Prinetti Date: Wed, 24 Jul 2024 11:25:33 +0200 Subject: [PATCH 015/429] chore: Set UNRELEASED user-agent Set a special header value to identify user agents built from the development branch. --- provider_client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/provider_client.go b/provider_client.go index a4a8dce51d..598596c61e 100644 --- a/provider_client.go +++ b/provider_client.go @@ -13,7 +13,7 @@ import ( // DefaultUserAgent is the default User-Agent string set in the request header. const ( - DefaultUserAgent = "gophercloud/v2.1.0" + DefaultUserAgent = "gophercloud/v3.0.0-UNRELEASED" DefaultMaxBackoffRetries = 60 ) From d8ce99fc1ccd0467b11e7abe1e38e43a70a0f3d5 Mon Sep 17 00:00:00 2001 From: whitefox Date: Wed, 24 Jul 2024 20:55:42 +0500 Subject: [PATCH 016/429] fix: create security group rule with any protocol https://github.com/gophercloud/gophercloud/issues/2442 --- .../v2/extensions/security/rules/requests.go | 5 ++ .../security/rules/testing/requests_test.go | 60 +++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/openstack/networking/v2/extensions/security/rules/requests.go b/openstack/networking/v2/extensions/security/rules/requests.go index 78b67b0df0..d9079dd96a 100644 --- a/openstack/networking/v2/extensions/security/rules/requests.go +++ b/openstack/networking/v2/extensions/security/rules/requests.go @@ -145,6 +145,11 @@ func Create(ctx context.Context, c *gophercloud.ServiceClient, opts CreateOptsBu r.Err = err return } + if m, mOk := b["security_group_rule"].(map[string]any); mOk { + if p, ok := m["protocol"]; ok && p == "any" { + m["protocol"] = nil + } + } resp, err := c.Post(ctx, rootURL(c), b, &r.Body, nil) _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return diff --git a/openstack/networking/v2/extensions/security/rules/testing/requests_test.go b/openstack/networking/v2/extensions/security/rules/testing/requests_test.go index 454399f306..7d9ceefdff 100644 --- a/openstack/networking/v2/extensions/security/rules/testing/requests_test.go +++ b/openstack/networking/v2/extensions/security/rules/testing/requests_test.go @@ -164,6 +164,66 @@ func TestCreate(t *testing.T) { th.AssertNoErr(t, err) } +func TestCreateAnyProtocol(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + + th.Mux.HandleFunc("/v2.0/security-group-rules", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestJSONRequest(t, r, ` +{ + "security_group_rule": { + "description": "test description of rule", + "direction": "ingress", + "port_range_min": 80, + "ethertype": "IPv4", + "port_range_max": 80, + "protocol": null, + "remote_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "security_group_id": "a7734e61-b545-452d-a3cd-0189cbd9747a" + } +} + `) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + + fmt.Fprintf(w, ` +{ + "security_group_rule": { + "description": "test description of rule", + "direction": "ingress", + "ethertype": "IPv4", + "id": "2bc0accf-312e-429a-956e-e4407625eb62", + "port_range_max": 80, + "port_range_min": 80, + "protocol": null, + "remote_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "remote_ip_prefix": null, + "security_group_id": "a7734e61-b545-452d-a3cd-0189cbd9747a", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + } +} + `) + }) + + opts := rules.CreateOpts{ + Description: "test description of rule", + Direction: "ingress", + PortRangeMin: 80, + EtherType: rules.EtherType4, + PortRangeMax: 80, + Protocol: "any", + RemoteGroupID: "85cc3048-abc3-43cc-89b3-377341426ac5", + SecGroupID: "a7734e61-b545-452d-a3cd-0189cbd9747a", + } + _, err := rules.Create(context.TODO(), fake.ServiceClient(), opts).Extract() + th.AssertNoErr(t, err) +} + func TestRequiredCreateOpts(t *testing.T) { res := rules.Create(context.TODO(), fake.ServiceClient(), rules.CreateOpts{Direction: rules.DirIngress}) if res.Err == nil { From d94838e603995807253e64d4915e37b9b7c34c48 Mon Sep 17 00:00:00 2001 From: whitefox Date: Wed, 24 Jul 2024 21:07:47 +0500 Subject: [PATCH 017/429] use const --- openstack/networking/v2/extensions/security/rules/requests.go | 2 +- .../v2/extensions/security/rules/testing/requests_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openstack/networking/v2/extensions/security/rules/requests.go b/openstack/networking/v2/extensions/security/rules/requests.go index d9079dd96a..8fa5d9ee83 100644 --- a/openstack/networking/v2/extensions/security/rules/requests.go +++ b/openstack/networking/v2/extensions/security/rules/requests.go @@ -146,7 +146,7 @@ func Create(ctx context.Context, c *gophercloud.ServiceClient, opts CreateOptsBu return } if m, mOk := b["security_group_rule"].(map[string]any); mOk { - if p, ok := m["protocol"]; ok && p == "any" { + if p, ok := m["protocol"]; ok && p == string(ProtocolAny) { m["protocol"] = nil } } diff --git a/openstack/networking/v2/extensions/security/rules/testing/requests_test.go b/openstack/networking/v2/extensions/security/rules/testing/requests_test.go index 7d9ceefdff..3b44db3837 100644 --- a/openstack/networking/v2/extensions/security/rules/testing/requests_test.go +++ b/openstack/networking/v2/extensions/security/rules/testing/requests_test.go @@ -216,7 +216,7 @@ func TestCreateAnyProtocol(t *testing.T) { PortRangeMin: 80, EtherType: rules.EtherType4, PortRangeMax: 80, - Protocol: "any", + Protocol: rules.ProtocolAny, RemoteGroupID: "85cc3048-abc3-43cc-89b3-377341426ac5", SecGroupID: "a7734e61-b545-452d-a3cd-0189cbd9747a", } From 856bb3140c17a3c406b4190bac6b67b125c78ff7 Mon Sep 17 00:00:00 2001 From: whitefox Date: Wed, 24 Jul 2024 23:11:12 +0500 Subject: [PATCH 018/429] move to ToSecGroupRuleCreateMap --- .../v2/extensions/security/rules/requests.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/openstack/networking/v2/extensions/security/rules/requests.go b/openstack/networking/v2/extensions/security/rules/requests.go index 8fa5d9ee83..cad532bd93 100644 --- a/openstack/networking/v2/extensions/security/rules/requests.go +++ b/openstack/networking/v2/extensions/security/rules/requests.go @@ -134,7 +134,16 @@ type CreateOpts struct { // ToSecGroupRuleCreateMap builds a request body from CreateOpts. func (opts CreateOpts) ToSecGroupRuleCreateMap() (map[string]any, error) { - return gophercloud.BuildRequestBody(opts, "security_group_rule") + b, err := gophercloud.BuildRequestBody(opts, "security_group_rule") + if err != nil { + return nil, err + } + if m, mOk := b["security_group_rule"].(map[string]any); mOk { + if p, ok := m["protocol"]; ok && p == string(ProtocolAny) { + m["protocol"] = nil + } + } + return b, err } // Create is an operation which adds a new security group rule and associates it @@ -145,11 +154,6 @@ func Create(ctx context.Context, c *gophercloud.ServiceClient, opts CreateOptsBu r.Err = err return } - if m, mOk := b["security_group_rule"].(map[string]any); mOk { - if p, ok := m["protocol"]; ok && p == string(ProtocolAny) { - m["protocol"] = nil - } - } resp, err := c.Post(ctx, rootURL(c), b, &r.Body, nil) _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return From c28246a6fe47a5a9d0cd7a1a729f7a6b36fb44f2 Mon Sep 17 00:00:00 2001 From: whitefox Date: Wed, 24 Jul 2024 23:44:21 +0500 Subject: [PATCH 019/429] emoved redundant key check --- .../networking/v2/extensions/security/rules/requests.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/openstack/networking/v2/extensions/security/rules/requests.go b/openstack/networking/v2/extensions/security/rules/requests.go index cad532bd93..55a6cde88f 100644 --- a/openstack/networking/v2/extensions/security/rules/requests.go +++ b/openstack/networking/v2/extensions/security/rules/requests.go @@ -2,6 +2,7 @@ package rules import ( "context" + "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/fwaas_v2/rules" "github.com/gophercloud/gophercloud/v2" "github.com/gophercloud/gophercloud/v2/pagination" @@ -138,10 +139,8 @@ func (opts CreateOpts) ToSecGroupRuleCreateMap() (map[string]any, error) { if err != nil { return nil, err } - if m, mOk := b["security_group_rule"].(map[string]any); mOk { - if p, ok := m["protocol"]; ok && p == string(ProtocolAny) { - m["protocol"] = nil - } + if m := b["security_group_rule"].(map[string]any); m["protocol"] == string(rules.ProtocolAny) { + m["protocol"] = nil } return b, err } From 1f7c5ec3fc309c0ac6e3ed845d30b4d55aed701f Mon Sep 17 00:00:00 2001 From: whitefox Date: Thu, 25 Jul 2024 00:34:18 +0500 Subject: [PATCH 020/429] extract ProtocolAny --- openstack/networking/v2/extensions/security/rules/results.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openstack/networking/v2/extensions/security/rules/results.go b/openstack/networking/v2/extensions/security/rules/results.go index cfdb27fa17..bcaea974ce 100644 --- a/openstack/networking/v2/extensions/security/rules/results.go +++ b/openstack/networking/v2/extensions/security/rules/results.go @@ -109,6 +109,9 @@ func (r commonResult) Extract() (*SecGroupRule, error) { SecGroupRule *SecGroupRule `json:"security_group_rule"` } err := r.ExtractInto(&s) + if err == nil && len(s.SecGroupRule.Protocol) == 0 { + s.SecGroupRule.Protocol = string(ProtocolAny) + } return s.SecGroupRule, err } From 58b35241d21d3681939a66cff69d03e481ab3f0e Mon Sep 17 00:00:00 2001 From: whitefox Date: Fri, 26 Jul 2024 22:57:11 +0500 Subject: [PATCH 021/429] protocol any to empty string --- .../v2/extensions/security/rules/requests.go | 13 ++----------- .../v2/extensions/security/rules/results.go | 3 --- .../security/rules/testing/requests_test.go | 2 -- 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/openstack/networking/v2/extensions/security/rules/requests.go b/openstack/networking/v2/extensions/security/rules/requests.go index 55a6cde88f..eaf6deab80 100644 --- a/openstack/networking/v2/extensions/security/rules/requests.go +++ b/openstack/networking/v2/extensions/security/rules/requests.go @@ -2,8 +2,6 @@ package rules import ( "context" - "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/fwaas_v2/rules" - "github.com/gophercloud/gophercloud/v2" "github.com/gophercloud/gophercloud/v2/pagination" ) @@ -78,7 +76,7 @@ const ( ProtocolUDP RuleProtocol = "udp" ProtocolUDPLite RuleProtocol = "udplite" ProtocolVRRP RuleProtocol = "vrrp" - ProtocolAny RuleProtocol = "any" + ProtocolAny RuleProtocol = "" ) // CreateOptsBuilder allows extensions to add additional parameters to the @@ -135,14 +133,7 @@ type CreateOpts struct { // ToSecGroupRuleCreateMap builds a request body from CreateOpts. func (opts CreateOpts) ToSecGroupRuleCreateMap() (map[string]any, error) { - b, err := gophercloud.BuildRequestBody(opts, "security_group_rule") - if err != nil { - return nil, err - } - if m := b["security_group_rule"].(map[string]any); m["protocol"] == string(rules.ProtocolAny) { - m["protocol"] = nil - } - return b, err + return gophercloud.BuildRequestBody(opts, "security_group_rule") } // Create is an operation which adds a new security group rule and associates it diff --git a/openstack/networking/v2/extensions/security/rules/results.go b/openstack/networking/v2/extensions/security/rules/results.go index bcaea974ce..cfdb27fa17 100644 --- a/openstack/networking/v2/extensions/security/rules/results.go +++ b/openstack/networking/v2/extensions/security/rules/results.go @@ -109,9 +109,6 @@ func (r commonResult) Extract() (*SecGroupRule, error) { SecGroupRule *SecGroupRule `json:"security_group_rule"` } err := r.ExtractInto(&s) - if err == nil && len(s.SecGroupRule.Protocol) == 0 { - s.SecGroupRule.Protocol = string(ProtocolAny) - } return s.SecGroupRule, err } diff --git a/openstack/networking/v2/extensions/security/rules/testing/requests_test.go b/openstack/networking/v2/extensions/security/rules/testing/requests_test.go index 3b44db3837..40372c298a 100644 --- a/openstack/networking/v2/extensions/security/rules/testing/requests_test.go +++ b/openstack/networking/v2/extensions/security/rules/testing/requests_test.go @@ -181,7 +181,6 @@ func TestCreateAnyProtocol(t *testing.T) { "port_range_min": 80, "ethertype": "IPv4", "port_range_max": 80, - "protocol": null, "remote_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", "security_group_id": "a7734e61-b545-452d-a3cd-0189cbd9747a" } @@ -200,7 +199,6 @@ func TestCreateAnyProtocol(t *testing.T) { "id": "2bc0accf-312e-429a-956e-e4407625eb62", "port_range_max": 80, "port_range_min": 80, - "protocol": null, "remote_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", "remote_ip_prefix": null, "security_group_id": "a7734e61-b545-452d-a3cd-0189cbd9747a", From 97ea7e1a84e7071c5d4e488576528429e6629db9 Mon Sep 17 00:00:00 2001 From: whitefox Date: Fri, 26 Jul 2024 23:52:25 +0500 Subject: [PATCH 022/429] revert newline --- openstack/networking/v2/extensions/security/rules/requests.go | 1 + 1 file changed, 1 insertion(+) diff --git a/openstack/networking/v2/extensions/security/rules/requests.go b/openstack/networking/v2/extensions/security/rules/requests.go index eaf6deab80..f2ea9f2d16 100644 --- a/openstack/networking/v2/extensions/security/rules/requests.go +++ b/openstack/networking/v2/extensions/security/rules/requests.go @@ -2,6 +2,7 @@ package rules import ( "context" + "github.com/gophercloud/gophercloud/v2" "github.com/gophercloud/gophercloud/v2/pagination" ) From fdb400d7bdc4d741870b259b5ca1cda0b8128ad8 Mon Sep 17 00:00:00 2001 From: kayrus Date: Sat, 27 Jul 2024 12:15:17 +0200 Subject: [PATCH 023/429] [containerinfra]: add "MasterLBEnabled" in Cluster results --- .../acceptance/openstack/containerinfra/v1/clusters_test.go | 1 + openstack/containerinfra/v1/clusters/results.go | 1 + .../containerinfra/v1/clusters/testing/fixtures_test.go | 5 +++++ 3 files changed, 7 insertions(+) diff --git a/internal/acceptance/openstack/containerinfra/v1/clusters_test.go b/internal/acceptance/openstack/containerinfra/v1/clusters_test.go index 7a277b318a..d12c31bf4a 100644 --- a/internal/acceptance/openstack/containerinfra/v1/clusters_test.go +++ b/internal/acceptance/openstack/containerinfra/v1/clusters_test.go @@ -63,6 +63,7 @@ func TestClustersCRUD(t *testing.T) { newCluster, err := clusters.Get(context.TODO(), client, clusterID).Extract() th.AssertNoErr(t, err) th.AssertEquals(t, newCluster.UUID, clusterID) + th.AssertEquals(t, newCluster.MasterLBEnabled, false) allPagesDetail, err := clusters.ListDetail(client, nil).AllPages(context.TODO()) th.AssertNoErr(t, err) diff --git a/openstack/containerinfra/v1/clusters/results.go b/openstack/containerinfra/v1/clusters/results.go index 6c235dcd23..04adc8ea48 100644 --- a/openstack/containerinfra/v1/clusters/results.go +++ b/openstack/containerinfra/v1/clusters/results.go @@ -112,6 +112,7 @@ type Cluster struct { UpdatedAt time.Time `json:"updated_at"` UserID string `json:"user_id"` FloatingIPEnabled bool `json:"floating_ip_enabled"` + MasterLBEnabled bool `json:"master_lb_enabled"` FixedNetwork string `json:"fixed_network"` FixedSubnet string `json:"fixed_subnet"` HealthStatus string `json:"health_status"` diff --git a/openstack/containerinfra/v1/clusters/testing/fixtures_test.go b/openstack/containerinfra/v1/clusters/testing/fixtures_test.go index 640533e2c8..ccbfddfc6d 100644 --- a/openstack/containerinfra/v1/clusters/testing/fixtures_test.go +++ b/openstack/containerinfra/v1/clusters/testing/fixtures_test.go @@ -50,6 +50,7 @@ var ExpectedCluster = clusters.Cluster{ UpdatedAt: time.Date(2016, 8, 29, 6, 53, 24, 0, time.UTC), UUID: clusterUUID, FloatingIPEnabled: true, + MasterLBEnabled: true, FixedNetwork: "private_network", FixedSubnet: "private_subnet", HealthStatus: "HEALTHY", @@ -85,6 +86,7 @@ var ExpectedCluster2 = clusters.Cluster{ UpdatedAt: time.Date(2016, 8, 29, 6, 53, 24, 0, time.UTC), UUID: clusterUUID2, FloatingIPEnabled: true, + MasterLBEnabled: true, FixedNetwork: "private_network", FixedSubnet: "private_subnet", HealthStatus: "HEALTHY", @@ -152,6 +154,7 @@ var ClusterGetResponse = fmt.Sprintf(` "create_timeout":60, "name":"k8s", "floating_ip_enabled": true, + "master_lb_enabled": true, "fixed_network": "private_network", "fixed_subnet": "private_subnet", "health_status": "HEALTHY", @@ -194,6 +197,7 @@ var ClusterListResponse = fmt.Sprintf(` "updated_at":"2016-08-29T06:53:24+00:00", "uuid":"%s", "floating_ip_enabled": true, + "master_lb_enabled": true, "fixed_network": "private_network", "fixed_subnet": "private_subnet", "health_status": "HEALTHY", @@ -232,6 +236,7 @@ var ClusterListResponse = fmt.Sprintf(` "updated_at":null, "uuid":"%s", "floating_ip_enabled": true, + "master_lb_enabled": true, "fixed_network": "private_network", "fixed_subnet": "private_subnet", "health_status": "HEALTHY", From 614749bde00060baee8430cfb3d5440c1f34268c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Aug 2024 09:11:02 +0000 Subject: [PATCH 024/429] build(deps): bump golang.org/x/crypto from 0.25.0 to 0.26.0 Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.25.0 to 0.26.0. - [Commits](https://github.com/golang/crypto/compare/v0.25.0...v0.26.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index d4ac50a838..1a02e360ff 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module github.com/gophercloud/gophercloud/v2 go 1.22 require ( - golang.org/x/crypto v0.25.0 + golang.org/x/crypto v0.26.0 gopkg.in/yaml.v2 v2.4.0 ) -require golang.org/x/sys v0.22.0 // indirect +require golang.org/x/sys v0.23.0 // indirect diff --git a/go.sum b/go.sum index 1e1f48a722..70de9bd3f3 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ -golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= -golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= -golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= -golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= -golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= +golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= +golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= From 8b63747ce6d4214f5dc78242fe4556f6d1295b23 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Sep 2024 09:44:59 +0000 Subject: [PATCH 025/429] build(deps): bump getsentry/action-github-app-token from 3.0.0 to 3.1.0 Bumps [getsentry/action-github-app-token](https://github.com/getsentry/action-github-app-token) from 3.0.0 to 3.1.0. - [Release notes](https://github.com/getsentry/action-github-app-token/releases) - [Commits](https://github.com/getsentry/action-github-app-token/compare/d4b5da6c5e37703f8c3b3e43abb5705b46e159cc...a0061014b82a6a5d6aeeb3b824aced47e3c3a7ef) --- updated-dependencies: - dependency-name: getsentry/action-github-app-token dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/backport.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/backport.yaml b/.github/workflows/backport.yaml index f690f497fe..0071ecba1d 100644 --- a/.github/workflows/backport.yaml +++ b/.github/workflows/backport.yaml @@ -25,7 +25,7 @@ jobs: steps: - name: Generate a token from the gophercloud-backport-bot github-app id: generate_token - uses: getsentry/action-github-app-token@d4b5da6c5e37703f8c3b3e43abb5705b46e159cc + uses: getsentry/action-github-app-token@a0061014b82a6a5d6aeeb3b824aced47e3c3a7ef with: app_id: ${{ secrets.BACKPORT_APP_ID }} private_key: ${{ secrets.BACKPORT_APP_PRIVATE_KEY }} @@ -84,7 +84,7 @@ jobs: steps: - name: Generate a token from the gophercloud-backport-bot github-app id: generate_token - uses: getsentry/action-github-app-token@d4b5da6c5e37703f8c3b3e43abb5705b46e159cc + uses: getsentry/action-github-app-token@a0061014b82a6a5d6aeeb3b824aced47e3c3a7ef with: app_id: ${{ secrets.BACKPORT_APP_ID }} private_key: ${{ secrets.BACKPORT_APP_PRIVATE_KEY }} From e3ae7f55a1f7f5abbc5c5207e5858ccab68b01ac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Sep 2024 09:58:44 +0000 Subject: [PATCH 026/429] build(deps): bump golang.org/x/crypto from 0.26.0 to 0.27.0 Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.26.0 to 0.27.0. - [Commits](https://github.com/golang/crypto/compare/v0.26.0...v0.27.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 1a02e360ff..0f39082357 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module github.com/gophercloud/gophercloud/v2 go 1.22 require ( - golang.org/x/crypto v0.26.0 + golang.org/x/crypto v0.27.0 gopkg.in/yaml.v2 v2.4.0 ) -require golang.org/x/sys v0.23.0 // indirect +require golang.org/x/sys v0.25.0 // indirect diff --git a/go.sum b/go.sum index 70de9bd3f3..77cbe99406 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= -golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= -golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= -golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= +golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= From 1ea105cd5789d35c2a67b5744746813d5832369a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Wed, 11 Sep 2024 17:16:00 +0200 Subject: [PATCH 027/429] migration.md: exclude vendor directory for automated script --- docs/MIGRATING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/MIGRATING.md b/docs/MIGRATING.md index c398cf0e65..75c4724a95 100644 --- a/docs/MIGRATING.md +++ b/docs/MIGRATING.md @@ -519,7 +519,7 @@ blockstorageversion=v3 openstack='github.com/gophercloud/gophercloud/openstack' openstack_utils='github.com/gophercloud/utils/openstack' -find . -type f -name '*.go' -exec sed -i ' +find . -type f -name '*.go' -not -path "*/vendor/*" -exec sed -i ' /^import ($/,/^)$/ { # 1: These packages have been removed and their functionality moved into the main module for the corresponding service. From 02a183d94c57799aadd77cad6fd76bb339309c03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Wed, 11 Sep 2024 17:18:03 +0200 Subject: [PATCH 028/429] migration.md: try converting more error types We should try converting all ErrDefaultXXX errors that existed in gophercloud v1 to their net/http equivalent. --- docs/MIGRATING.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/MIGRATING.md b/docs/MIGRATING.md index 75c4724a95..7bf4ed9708 100644 --- a/docs/MIGRATING.md +++ b/docs/MIGRATING.md @@ -611,8 +611,19 @@ find . -type f -name '*.go' -not -path "*/vendor/*" -exec sed -i ' # 8: Rename identifiers that were changed in v2 s#\(\(volumes\|servers\)\.SchedulerHint\)s#\2.SchedulerHintOpts#g - # 9: Tentatively replace error handling for 404s + # 9: Tentatively replace error handling + s#\(\t\+\)if _, ok := err.(gophercloud.ErrDefault400); \(!\?\)ok {#\1if \2gophercloud.ResponseCodeIs(err, http.StatusBadRequest) {#g + s#\(\t\+\)if _, ok := err.(gophercloud.ErrDefault401); \(!\?\)ok {#\1if \2gophercloud.ResponseCodeIs(err, http.StatusUnauthorized) {#g + s#\(\t\+\)if _, ok := err.(gophercloud.ErrDefault403); \(!\?\)ok {#\1if \2gophercloud.ResponseCodeIs(err, http.StatusForbidden) {#g s#\(\t\+\)if _, ok := err.(gophercloud.ErrDefault404); \(!\?\)ok {#\1if \2gophercloud.ResponseCodeIs(err, http.StatusNotFound) {#g + s#\(\t\+\)if _, ok := err.(gophercloud.ErrDefault405); \(!\?\)ok {#\1if \2gophercloud.ResponseCodeIs(err, http.StatusMethodNotAllowed) {#g + s#\(\t\+\)if _, ok := err.(gophercloud.ErrDefault408); \(!\?\)ok {#\1if \2gophercloud.ResponseCodeIs(err, http.StatusRequestTimeout) {#g + s#\(\t\+\)if _, ok := err.(gophercloud.ErrDefault409); \(!\?\)ok {#\1if \2gophercloud.ResponseCodeIs(err, http.StatusConflict) {#g + s#\(\t\+\)if _, ok := err.(gophercloud.ErrDefault429); \(!\?\)ok {#\1if \2gophercloud.ResponseCodeIs(err, http.StatusTooManyRequests) {#g + s#\(\t\+\)if _, ok := err.(gophercloud.ErrDefault500); \(!\?\)ok {#\1if \2gophercloud.ResponseCodeIs(err, http.StatusInternalServerError) {#g + s#\(\t\+\)if _, ok := err.(gophercloud.ErrDefault502); \(!\?\)ok {#\1if \2gophercloud.ResponseCodeIs(err, http.StatusBadGateway) {#g + s#\(\t\+\)if _, ok := err.(gophercloud.ErrDefault503); \(!\?\)ok {#\1if \2gophercloud.ResponseCodeIs(err, http.StatusServiceUnavailable) {#g + s#\(\t\+\)if _, ok := err.(gophercloud.ErrDefault504); \(!\?\)ok {#\1if \2gophercloud.ResponseCodeIs(err, http.StatusGatewayTimeout) {#g } ' {} \; From c8233ba73c5d5b72f4369bc5a664f13f464ea187 Mon Sep 17 00:00:00 2001 From: kayrus Date: Mon, 23 Sep 2024 23:00:36 +0200 Subject: [PATCH 029/429] octavia: add new security options to pools and listeners --- .../loadbalancer/v2/listeners/requests.go | 80 +++++++++++++++++++ .../loadbalancer/v2/listeners/results.go | 18 +++++ openstack/loadbalancer/v2/pools/requests.go | 62 ++++++++++++++ openstack/loadbalancer/v2/pools/results.go | 31 +++++++ 4 files changed, 191 insertions(+) diff --git a/openstack/loadbalancer/v2/listeners/requests.go b/openstack/loadbalancer/v2/listeners/requests.go index ea5b10dd2f..5c66db23be 100644 --- a/openstack/loadbalancer/v2/listeners/requests.go +++ b/openstack/loadbalancer/v2/listeners/requests.go @@ -170,6 +170,46 @@ type CreateOpts struct { // A list of IPv4, IPv6 or mix of both CIDRs AllowedCIDRs []string `json:"allowed_cidrs,omitempty"` + // A list of ALPN protocols. Available protocols: http/1.0, http/1.1, + // h2. Available from microversion 2.20. + ALPNProtocols []string `json:"alpn_protocols,omitempty"` + + // The TLS client authentication mode. One of the options NONE, + // OPTIONAL or MANDATORY. Available from microversion 2.8. + ClientAuthentication string `json:"client_authentication,omitempty"` + + // The ref of the key manager service secret containing a PEM format + // client CA certificate bundle for TERMINATED_HTTPS listeners. + // Available from microversion 2.8. + ClientCATLSContainerRef string `json:"client_ca_tls_container_ref,omitempty"` + + // The URI of the key manager service secret containing a PEM format CA + // revocation list file for TERMINATED_HTTPS listeners. Available from + // microversion 2.8. + ClientCRLContainerRef string `json:"client_crl_container_ref,omitempty"` + + // Defines whether the includeSubDomains directive should be added to + // the Strict-Transport-Security HTTP response header. This requires + // setting the hsts_max_age option as well in order to become + // effective. Available from microversion 2.27. + HSTSIncludeSubdomains bool `json:"hsts_include_subdomains,omitempty"` + + // The value of the max_age directive for the Strict-Transport-Security + // HTTP response header. Setting this enables HTTP Strict Transport + // Security (HSTS) for the TLS-terminated listener. Available from + // microversion 2.27. + HSTSMaxAge int `json:"hsts_max_age,omitempty"` + + // Defines whether the preload directive should be added to the + // Strict-Transport-Security HTTP response header. This requires + // setting the hsts_max_age option as well in order to become + // effective. Available from microversion 2.27. + HSTSPreload bool `json:"hsts_preload,omitempty"` + + // List of ciphers in OpenSSL format (colon-separated). Available from + // microversion 2.15. + TLSCiphers string `json:"tls_ciphers,omitempty"` + // A list of TLS protocol versions. Available from microversion 2.17 TLSVersions []TLSVersion `json:"tls_versions,omitempty"` @@ -255,6 +295,46 @@ type UpdateOpts struct { // A list of IPv4, IPv6 or mix of both CIDRs AllowedCIDRs *[]string `json:"allowed_cidrs,omitempty"` + // A list of ALPN protocols. Available protocols: http/1.0, http/1.1, + // h2. Available from microversion 2.20. + ALPNProtocols *[]string `json:"alpn_protocols,omitempty"` + + // The TLS client authentication mode. One of the options NONE, + // OPTIONAL or MANDATORY. Available from microversion 2.8. + ClientAuthentication *string `json:"client_authentication,omitempty"` + + // The ref of the key manager service secret containing a PEM format + // client CA certificate bundle for TERMINATED_HTTPS listeners. + // Available from microversion 2.8. + ClientCATLSContainerRef *string `json:"client_ca_tls_container_ref,omitempty"` + + // The URI of the key manager service secret containing a PEM format CA + // revocation list file for TERMINATED_HTTPS listeners. Available from + // microversion 2.8. + ClientCRLContainerRef *string `json:"client_crl_container_ref,omitempty"` + + // Defines whether the includeSubDomains directive should be added to + // the Strict-Transport-Security HTTP response header. This requires + // setting the hsts_max_age option as well in order to become + // effective. Available from microversion 2.27. + HSTSIncludeSubdomains *bool `json:"hsts_include_subdomains,omitempty"` + + // The value of the max_age directive for the Strict-Transport-Security + // HTTP response header. Setting this enables HTTP Strict Transport + // Security (HSTS) for the TLS-terminated listener. Available from + // microversion 2.27. + HSTSMaxAge *int `json:"hsts_max_age,omitempty"` + + // Defines whether the preload directive should be added to the + // Strict-Transport-Security HTTP response header. This requires + // setting the hsts_max_age option as well in order to become + // effective. Available from microversion 2.27. + HSTSPreload *bool `json:"hsts_preload,omitempty"` + + // List of ciphers in OpenSSL format (colon-separated). Available from + // microversion 2.15. + TLSCiphers *string `json:"tls_ciphers,omitempty"` + // A list of TLS protocol versions. Available from microversion 2.17 TLSVersions *[]TLSVersion `json:"tls_versions,omitempty"` diff --git a/openstack/loadbalancer/v2/listeners/results.go b/openstack/loadbalancer/v2/listeners/results.go index 562a7618dd..0bd08f783a 100644 --- a/openstack/loadbalancer/v2/listeners/results.go +++ b/openstack/loadbalancer/v2/listeners/results.go @@ -114,6 +114,24 @@ type Listener struct { // New in version 2.8 ClientCRLContainerRef string `json:"client_crl_container_ref"` + // Defines whether the includeSubDomains directive should be added to + // the Strict-Transport-Security HTTP response header. This requires + // setting the hsts_max_age option as well in order to become + // effective. Available from microversion 2.27. + HSTSIncludeSubdomains bool `json:"hsts_include_subdomains"` + + // The value of the max_age directive for the Strict-Transport-Security + // HTTP response header. Setting this enables HTTP Strict Transport + // Security (HSTS) for the TLS-terminated listener. Available from + // microversion 2.27. + HSTSMaxAge int `json:"hsts_max_age"` + + // Defines whether the preload directive should be added to the + // Strict-Transport-Security HTTP response header. This requires + // setting the hsts_max_age option as well in order to become + // effective. Available from microversion 2.27. + HSTSPreload bool `json:"hsts_preload"` + // The operating status of the resource OperatingStatus string `json:"operating_status"` } diff --git a/openstack/loadbalancer/v2/pools/requests.go b/openstack/loadbalancer/v2/pools/requests.go index 452bfaddb9..60d1132eba 100644 --- a/openstack/loadbalancer/v2/pools/requests.go +++ b/openstack/loadbalancer/v2/pools/requests.go @@ -122,6 +122,37 @@ type CreateOpts struct { // Omit this field to prevent session persistence. Persistence *SessionPersistence `json:"session_persistence,omitempty"` + // A list of ALPN protocols. Available protocols: http/1.0, http/1.1, + // h2. Available from microversion 2.24. + ALPNProtocols []string `json:"alpn_protocols,omitempty"` + + // The reference of the key manager service secret containing a PEM + // format CA certificate bundle for tls_enabled pools. Available from + // microversion 2.8. + CATLSContainerRef string `json:"ca_tls_container_ref,omitempty"` + + // The reference of the key manager service secret containing a PEM + // format CA revocation list file for tls_enabled pools. Available from + // microversion 2.8. + CRLContainerRef string `json:"crl_container_ref,omitempty"` + + // When true connections to backend member servers will use TLS + // encryption. Default is false. Available from microversion 2.8. + TLSEnabled bool `json:"tls_enabled,omitempty"` + + // List of ciphers in OpenSSL format (colon-separated). Available from + // microversion 2.15. + TLSCiphers string `json:"tls_ciphers,omitempty"` + + // The reference to the key manager service secret containing a PKCS12 + // format certificate/key bundle for tls_enabled pools for TLS client + // authentication to the member servers. Available from microversion 2.8. + TLSContainerRef string `json:"tls_container_ref,omitempty"` + + // A list of TLS protocol versions. Available versions: SSLv3, TLSv1, + // TLSv1.1, TLSv1.2, TLSv1.3. Available from microversion 2.17. + TLSVersions []string `json:"tls_versions,omitempty"` + // The administrative state of the Pool. A valid value is true (UP) // or false (DOWN). AdminStateUp *bool `json:"admin_state_up,omitempty"` @@ -196,6 +227,37 @@ type UpdateOpts struct { // Persistence is the session persistence of the pool. Persistence *SessionPersistence `json:"session_persistence,omitempty"` + // A list of ALPN protocols. Available protocols: http/1.0, http/1.1, + // h2. Available from microversion 2.24. + ALPNProtocols *[]string `json:"alpn_protocols,omitempty"` + + // The reference of the key manager service secret containing a PEM + // format CA certificate bundle for tls_enabled pools. Available from + // microversion 2.8. + CATLSContainerRef *string `json:"ca_tls_container_ref,omitempty"` + + // The reference of the key manager service secret containing a PEM + // format CA revocation list file for tls_enabled pools. Available from + // microversion 2.8. + CRLContainerRef *string `json:"crl_container_ref,omitempty"` + + // When true connections to backend member servers will use TLS + // encryption. Default is false. Available from microversion 2.8. + TLSEnabled *bool `json:"tls_enabled,omitempty"` + + // List of ciphers in OpenSSL format (colon-separated). Available from + // microversion 2.15. + TLSCiphers *string `json:"tls_ciphers,omitempty"` + + // The reference to the key manager service secret containing a PKCS12 + // format certificate/key bundle for tls_enabled pools for TLS client + // authentication to the member servers. Available from microversion 2.8. + TLSContainerRef *string `json:"tls_container_ref,omitempty"` + + // A list of TLS protocol versions. Available versions: SSLv3, TLSv1, + // TLSv1.1, TLSv1.2, TLSv1.3. Available from microversion 2.17. + TLSVersions *[]string `json:"tls_versions,omitempty"` + // Tags is a set of resource tags. New in version 2.5 Tags *[]string `json:"tags,omitempty"` } diff --git a/openstack/loadbalancer/v2/pools/results.go b/openstack/loadbalancer/v2/pools/results.go index 1f27752e0d..bff336ea4a 100644 --- a/openstack/loadbalancer/v2/pools/results.go +++ b/openstack/loadbalancer/v2/pools/results.go @@ -95,6 +95,37 @@ type Pool struct { // same Pool member or not. Persistence SessionPersistence `json:"session_persistence"` + // A list of ALPN protocols. Available protocols: http/1.0, http/1.1, + // h2. Available from microversion 2.24. + ALPNProtocols []string `json:"alpn_protocols"` + + // The reference of the key manager service secret containing a PEM + // format CA certificate bundle for tls_enabled pools. Available from + // microversion 2.8. + CATLSContainerRef string `json:"ca_tls_container_ref"` + + // The reference of the key manager service secret containing a PEM + // format CA revocation list file for tls_enabled pools. Available from + // microversion 2.8. + CRLContainerRef string `json:"crl_container_ref"` + + // When true connections to backend member servers will use TLS + // encryption. Default is false. Available from microversion 2.8. + TLSEnabled bool `json:"tls_enabled"` + + // List of ciphers in OpenSSL format (colon-separated). Available from + // microversion 2.15. + TLSCiphers string `json:"tls_ciphers"` + + // The reference to the key manager service secret containing a PKCS12 + // format certificate/key bundle for tls_enabled pools for TLS client + // authentication to the member servers. Available from microversion 2.8. + TLSContainerRef string `json:"tls_container_ref"` + + // A list of TLS protocol versions. Available versions: SSLv3, TLSv1, + // TLSv1.1, TLSv1.2, TLSv1.3. Available from microversion 2.17. + TLSVersions []string `json:"tls_versions"` + // The load balancer provider. Provider string `json:"provider"` From 90c1d821799ca1950aaafa824c6f426463dcf51d Mon Sep 17 00:00:00 2001 From: kayrus Date: Tue, 24 Sep 2024 01:54:02 +0200 Subject: [PATCH 030/429] Allow unsetting certain parameters --- .../loadbalancer/v2/listeners/requests.go | 28 +++++++++++-- openstack/loadbalancer/v2/pools/requests.go | 39 +++++++++++++++++-- 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/openstack/loadbalancer/v2/listeners/requests.go b/openstack/loadbalancer/v2/listeners/requests.go index 5c66db23be..3216fbddd0 100644 --- a/openstack/loadbalancer/v2/listeners/requests.go +++ b/openstack/loadbalancer/v2/listeners/requests.go @@ -37,6 +37,15 @@ const ( TLSVersionTLSv1_3 TLSVersion = "TLSv1.3" ) +// ClientAuthentication represents the TLS client authentication mode. +type ClientAuthentication string + +const ( + ClientAuthenticationNone ClientAuthentication = "NONE" + ClientAuthenticationOptional ClientAuthentication = "OPTIONAL" + ClientAuthenticationMandatory ClientAuthentication = "MANDATORY" +) + // ListOptsBuilder allows extensions to add additional parameters to the // List request. type ListOptsBuilder interface { @@ -176,7 +185,7 @@ type CreateOpts struct { // The TLS client authentication mode. One of the options NONE, // OPTIONAL or MANDATORY. Available from microversion 2.8. - ClientAuthentication string `json:"client_authentication,omitempty"` + ClientAuthentication ClientAuthentication `json:"client_authentication,omitempty"` // The ref of the key manager service secret containing a PEM format // client CA certificate bundle for TERMINATED_HTTPS listeners. @@ -301,7 +310,7 @@ type UpdateOpts struct { // The TLS client authentication mode. One of the options NONE, // OPTIONAL or MANDATORY. Available from microversion 2.8. - ClientAuthentication *string `json:"client_authentication,omitempty"` + ClientAuthentication *ClientAuthentication `json:"client_authentication,omitempty"` // The ref of the key manager service secret containing a PEM format // client CA certificate bundle for TERMINATED_HTTPS listeners. @@ -349,10 +358,23 @@ func (opts UpdateOpts) ToListenerUpdateMap() (map[string]any, error) { return nil, err } - if m := b["listener"].(map[string]any); m["default_pool_id"] == "" { + m := b["listener"].(map[string]any) + + // allow to unset default_pool_id on empty string + if m["default_pool_id"] == "" { m["default_pool_id"] = nil } + // allow to unset alpn_protocols on empty slice + if opts.ALPNProtocols != nil && len(*opts.ALPNProtocols) == 0 { + m["alpn_protocols"] = nil + } + + // allow to unset tls_versions on empty slice + if opts.TLSVersions != nil && len(*opts.TLSVersions) == 0 { + m["tls_versions"] = nil + } + return b, nil } diff --git a/openstack/loadbalancer/v2/pools/requests.go b/openstack/loadbalancer/v2/pools/requests.go index 60d1132eba..3443686370 100644 --- a/openstack/loadbalancer/v2/pools/requests.go +++ b/openstack/loadbalancer/v2/pools/requests.go @@ -8,6 +8,17 @@ import ( "github.com/gophercloud/gophercloud/v2/pagination" ) +// Type TLSVersion represents a tls version +type TLSVersion string + +const ( + TLSVersionSSLv3 TLSVersion = "SSLv3" + TLSVersionTLSv1 TLSVersion = "TLSv1" + TLSVersionTLSv1_1 TLSVersion = "TLSv1.1" + TLSVersionTLSv1_2 TLSVersion = "TLSv1.2" + TLSVersionTLSv1_3 TLSVersion = "TLSv1.3" +) + // ListOptsBuilder allows extensions to add additional parameters to the // List request. type ListOptsBuilder interface { @@ -151,7 +162,7 @@ type CreateOpts struct { // A list of TLS protocol versions. Available versions: SSLv3, TLSv1, // TLSv1.1, TLSv1.2, TLSv1.3. Available from microversion 2.17. - TLSVersions []string `json:"tls_versions,omitempty"` + TLSVersions []TLSVersion `json:"tls_versions,omitempty"` // The administrative state of the Pool. A valid value is true (UP) // or false (DOWN). @@ -256,7 +267,7 @@ type UpdateOpts struct { // A list of TLS protocol versions. Available versions: SSLv3, TLSv1, // TLSv1.1, TLSv1.2, TLSv1.3. Available from microversion 2.17. - TLSVersions *[]string `json:"tls_versions,omitempty"` + TLSVersions *[]TLSVersion `json:"tls_versions,omitempty"` // Tags is a set of resource tags. New in version 2.5 Tags *[]string `json:"tags,omitempty"` @@ -264,7 +275,29 @@ type UpdateOpts struct { // ToPoolUpdateMap builds a request body from UpdateOpts. func (opts UpdateOpts) ToPoolUpdateMap() (map[string]any, error) { - return gophercloud.BuildRequestBody(opts, "pool") + b, err := gophercloud.BuildRequestBody(opts, "pool") + if err != nil { + return nil, err + } + + m := b["pool"].(map[string]any) + + // allow to unset session_persistence on empty SessionPersistence struct + if opts.Persistence != nil && *opts.Persistence == (SessionPersistence{}) { + m["session_persistence"] = nil + } + + // allow to unset alpn_protocols on empty slice + if opts.ALPNProtocols != nil && len(*opts.ALPNProtocols) == 0 { + m["alpn_protocols"] = nil + } + + // allow to unset tls_versions on empty slice + if opts.TLSVersions != nil && len(*opts.TLSVersions) == 0 { + m["tls_versions"] = nil + } + + return b, nil } // Update allows pools to be updated. From 11a3fcceab77cd1954e4f172fd075126e91e9011 Mon Sep 17 00:00:00 2001 From: kayrus Date: Tue, 24 Sep 2024 02:40:00 +0200 Subject: [PATCH 031/429] octavia: add new options to health monitors --- openstack/loadbalancer/v2/monitors/requests.go | 16 ++++++++++++++++ openstack/loadbalancer/v2/monitors/results.go | 6 ++++++ 2 files changed, 22 insertions(+) diff --git a/openstack/loadbalancer/v2/monitors/requests.go b/openstack/loadbalancer/v2/monitors/requests.go index 5667955add..be5701c5f4 100644 --- a/openstack/loadbalancer/v2/monitors/requests.go +++ b/openstack/loadbalancer/v2/monitors/requests.go @@ -119,6 +119,10 @@ type CreateOpts struct { // is not specified, it defaults to "GET". Required for HTTP(S) types. HTTPMethod string `json:"http_method,omitempty"` + // The HTTP version. One of 1.0 or 1.1. The default is 1.0. New in + // version 2.10. + HTTPVersion string `json:"http_version,omitempty"` + // Expected HTTP codes for a passing HTTP(S) Monitor. You can either specify // a single status like "200", a range like "200-202", or a combination like // "200-202, 401". @@ -139,6 +143,10 @@ type CreateOpts struct { // or false (DOWN). AdminStateUp *bool `json:"admin_state_up,omitempty"` + // The domain name, which be injected into the HTTP Host Header to the + // backend server for HTTP health check. New in version 2.10 + DomainName string `json:"domain_name,omitempty"` + // Tags is a set of resource tags. New in version 2.5 Tags []string `json:"tags,omitempty"` } @@ -213,6 +221,10 @@ type UpdateOpts struct { // is not specified, it defaults to "GET". Required for HTTP(S) types. HTTPMethod string `json:"http_method,omitempty"` + // The HTTP version. One of 1.0 or 1.1. The default is 1.0. New in + // version 2.10. + HTTPVersion *string `json:"http_version,omitempty"` + // Expected HTTP codes for a passing HTTP(S) Monitor. You can either specify // a single status like "200", or a range like "200-202". Required for HTTP(S) // types. @@ -221,6 +233,10 @@ type UpdateOpts struct { // The Name of the Monitor. Name *string `json:"name,omitempty"` + // The domain name, which be injected into the HTTP Host Header to the + // backend server for HTTP health check. New in version 2.10 + DomainName *string `json:"domain_name,omitempty"` + // The administrative state of the Monitor. A valid value is true (UP) // or false (DOWN). AdminStateUp *bool `json:"admin_state_up,omitempty"` diff --git a/openstack/loadbalancer/v2/monitors/results.go b/openstack/loadbalancer/v2/monitors/results.go index 3a29da9f40..644ef18700 100644 --- a/openstack/loadbalancer/v2/monitors/results.go +++ b/openstack/loadbalancer/v2/monitors/results.go @@ -60,6 +60,9 @@ type Monitor struct { // The HTTP method that the monitor uses for requests. HTTPMethod string `json:"http_method"` + // The HTTP version that the monitor uses for requests. + HTTPVersion string `json:"http_version"` + // The HTTP path of the request sent by the monitor to test the health of a // member. Must be a string beginning with a forward slash (/). URLPath string `json:"url_path" ` @@ -67,6 +70,9 @@ type Monitor struct { // Expected HTTP codes for a passing HTTP(S) monitor. ExpectedCodes string `json:"expected_codes"` + // The HTTP host header that the monitor uses for requests. + DomainName string `json:"domain_name"` + // The administrative state of the health monitor, which is up (true) or // down (false). AdminStateUp bool `json:"admin_state_up"` From 4d5dc1359a2c0ec9a2680374d5973fbac02e4d0d Mon Sep 17 00:00:00 2001 From: Paul des Garets Date: Fri, 29 Apr 2022 12:59:55 +0200 Subject: [PATCH 032/429] ObjectStorage v1: Add Sync headers --- openstack/objectstorage/v1/containers/results.go | 2 ++ openstack/objectstorage/v1/containers/testing/fixtures.go | 2 ++ openstack/objectstorage/v1/containers/testing/requests_test.go | 2 ++ 3 files changed, 6 insertions(+) diff --git a/openstack/objectstorage/v1/containers/results.go b/openstack/objectstorage/v1/containers/results.go index 8e71c15063..fddfa26bf1 100644 --- a/openstack/objectstorage/v1/containers/results.go +++ b/openstack/objectstorage/v1/containers/results.go @@ -111,6 +111,8 @@ type GetHeader struct { TempURLKey2 string `json:"X-Container-Meta-Temp-URL-Key-2"` Timestamp float64 `json:"X-Timestamp,string"` VersionsEnabled bool `json:"-"` + SyncKey string `json:"X-Sync-Key"` + SyncTo string `json:"X-Sync-To"` } func (r *GetHeader) UnmarshalJSON(b []byte) error { diff --git a/openstack/objectstorage/v1/containers/testing/fixtures.go b/openstack/objectstorage/v1/containers/testing/fixtures.go index 0f440472ac..ef6d45b03a 100644 --- a/openstack/objectstorage/v1/containers/testing/fixtures.go +++ b/openstack/objectstorage/v1/containers/testing/fixtures.go @@ -258,6 +258,8 @@ func HandleGetContainerSuccessfully(t *testing.T, options ...option) { w.Header().Set("X-Trans-Id", "tx554ed59667a64c61866f1-0057b4ba37") w.Header().Set("X-Storage-Policy", "test_policy") w.Header().Set("X-Versions-Enabled", "True") + w.Header().Set("X-Sync-Key", "272465181849") + w.Header().Set("X-Sync-To", "anotherContainer") w.WriteHeader(http.StatusNoContent) }) } diff --git a/openstack/objectstorage/v1/containers/testing/requests_test.go b/openstack/objectstorage/v1/containers/testing/requests_test.go index 9a2074d510..fedf0f2fe6 100644 --- a/openstack/objectstorage/v1/containers/testing/requests_test.go +++ b/openstack/objectstorage/v1/containers/testing/requests_test.go @@ -244,6 +244,8 @@ func TestGetContainer(t *testing.T) { StoragePolicy: "test_policy", Timestamp: 1471298837.95721, VersionsEnabled: true, + SyncKey: "272465181849", + SyncTo: "anotherContainer", } actual, err := res.Extract() th.AssertNoErr(t, err) From cec507c899d06801d7424c920f54793170ad5f32 Mon Sep 17 00:00:00 2001 From: Paul des Garets Date: Fri, 29 Apr 2022 13:00:13 +0200 Subject: [PATCH 033/429] Compute v2: Add locked status --- openstack/compute/v2/servers/results.go | 4 ++++ openstack/compute/v2/servers/testing/fixtures_test.go | 7 +++++-- openstack/compute/v2/servers/testing/requests_test.go | 2 ++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/openstack/compute/v2/servers/results.go b/openstack/compute/v2/servers/results.go index dc51564176..385001c8dd 100644 --- a/openstack/compute/v2/servers/results.go +++ b/openstack/compute/v2/servers/results.go @@ -279,6 +279,10 @@ type Server struct { // AvailabilityZone is the availabilty zone the server is in. AvailabilityZone string `json:"OS-EXT-AZ:availability_zone"` + + // Locked indicates the lock status of the server + // This requires microversion 2.9 or later + Locked *bool `json:"locked"` } type AttachedVolume struct { diff --git a/openstack/compute/v2/servers/testing/fixtures_test.go b/openstack/compute/v2/servers/testing/fixtures_test.go index 2ce6282b02..f3fd27fce3 100644 --- a/openstack/compute/v2/servers/testing/fixtures_test.go +++ b/openstack/compute/v2/servers/testing/fixtures_test.go @@ -158,7 +158,8 @@ const ServerListBody = ` "progress": 0, "OS-EXT-STS:power_state": 1, "config_drive": "", - "metadata": {} + "metadata": {}, + "locked": true }, { "status": "ACTIVE", @@ -297,7 +298,8 @@ const SingleServerBody = ` "progress": 0, "OS-EXT-STS:power_state": 1, "config_drive": "", - "metadata": {} + "metadata": {}, + "locked": true } } ` @@ -631,6 +633,7 @@ var ( TerminatedAt: time.Time{}, DiskConfig: servers.Manual, AvailabilityZone: "nova", + Locked: func() *bool { b := true; return &b }(), } ConsoleOutput = "abc" diff --git a/openstack/compute/v2/servers/testing/requests_test.go b/openstack/compute/v2/servers/testing/requests_test.go index b6ebefce5e..b50ea185c9 100644 --- a/openstack/compute/v2/servers/testing/requests_test.go +++ b/openstack/compute/v2/servers/testing/requests_test.go @@ -774,6 +774,7 @@ func TestGetFaultyServer(t *testing.T) { FaultyServer := ServerDerp FaultyServer.Fault = DerpFault + FaultyServer.Locked = nil th.CheckDeepEquals(t, FaultyServer, *actual) } @@ -1145,6 +1146,7 @@ func TestCreateServerWithTags(t *testing.T) { tags := []string{"foo", "bar"} ServerDerpTags := ServerDerp ServerDerpTags.Tags = &tags + ServerDerpTags.Locked = nil createOpts := servers.CreateOpts{ Name: "derp", From 5d1815c7404f24d98f74bf3ac0d8c5f9b0a2a547 Mon Sep 17 00:00:00 2001 From: Pierre Prinetti Date: Thu, 26 Sep 2024 17:36:28 +0200 Subject: [PATCH 034/429] Add label: just-needs-tests Several pull requests in the backlog are code-complete according to their authors, but lack tests. This label will let us be more aware of the problem. --- .github/labels.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/labels.yaml b/.github/labels.yaml index 4f888b4d4f..ad21863831 100644 --- a/.github/labels.yaml +++ b/.github/labels.yaml @@ -22,6 +22,9 @@ - color: 'F9D0C4' description: Additional information requested name: needinfo +- color: 'FEF2C0' + description: This PR lacks tests before it can be merged + name: just-needs-tests - color: '30ABB9' description: This PR targets v1 From 9c94b9596001f0046de88468543870a417b3dbe4 Mon Sep 17 00:00:00 2001 From: kayrus Date: Thu, 26 Sep 2024 22:09:13 +0200 Subject: [PATCH 035/429] [core]: handle empty response body --- openstack/networking/v2/extensions/bgp/speakers/requests.go | 4 ++-- .../v2/extensions/bgp/speakers/testing/requests_test.go | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/openstack/networking/v2/extensions/bgp/speakers/requests.go b/openstack/networking/v2/extensions/bgp/speakers/requests.go index 4c352c2cc3..b6dd26d909 100644 --- a/openstack/networking/v2/extensions/bgp/speakers/requests.go +++ b/openstack/networking/v2/extensions/bgp/speakers/requests.go @@ -142,7 +142,7 @@ func RemoveBGPPeer(ctx context.Context, c *gophercloud.ServiceClient, bgpSpeaker r.Err = err return } - resp, err := c.Put(ctx, removeBGPPeerURL(c, bgpSpeakerID), b, &r.Body, &gophercloud.RequestOpts{ + resp, err := c.Put(ctx, removeBGPPeerURL(c, bgpSpeakerID), b, nil, &gophercloud.RequestOpts{ OkCodes: []int{200}, }) _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) @@ -207,7 +207,7 @@ func RemoveGatewayNetwork(ctx context.Context, c *gophercloud.ServiceClient, bgp r.Err = err return } - resp, err := c.Put(ctx, removeGatewayNetworkURL(c, bgpSpeakerID), b, &r.Body, &gophercloud.RequestOpts{ + resp, err := c.Put(ctx, removeGatewayNetworkURL(c, bgpSpeakerID), b, nil, &gophercloud.RequestOpts{ OkCodes: []int{200}, }) _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) diff --git a/openstack/networking/v2/extensions/bgp/speakers/testing/requests_test.go b/openstack/networking/v2/extensions/bgp/speakers/testing/requests_test.go index 9e8df52b0c..d163086a8a 100644 --- a/openstack/networking/v2/extensions/bgp/speakers/testing/requests_test.go +++ b/openstack/networking/v2/extensions/bgp/speakers/testing/requests_test.go @@ -3,7 +3,6 @@ package testing import ( "context" "fmt" - "io" "net/http" "testing" @@ -195,7 +194,7 @@ func TestRemoveBGPPeer(t *testing.T) { opts := speakers.RemoveBGPPeerOpts{BGPPeerID: bgpPeerID} err := speakers.RemoveBGPPeer(context.TODO(), fake.ServiceClient(), bgpSpeakerID, opts).ExtractErr() - th.AssertEquals(t, err, io.EOF) + th.AssertNoErr(t, err) } func TestGetAdvertisedRoutes(t *testing.T) { @@ -279,5 +278,5 @@ func TestRemoveGatewayNetwork(t *testing.T) { opts := speakers.RemoveGatewayNetworkOpts{NetworkID: networkID} err := speakers.RemoveGatewayNetwork(context.TODO(), fake.ServiceClient(), bgpSpeakerID, opts).ExtractErr() - th.AssertEquals(t, err, io.EOF) + th.AssertNoErr(t, err) } From 3e74ae8989100d2399f2158fc9c65a9dc53a2138 Mon Sep 17 00:00:00 2001 From: kayrus Date: Thu, 26 Sep 2024 23:52:53 +0200 Subject: [PATCH 036/429] [core]: proper ParseResponse handling --- .../v2/extensions/fwaas_v2/groups/requests.go | 18 ++++++++++++------ .../extensions/fwaas_v2/policies/requests.go | 18 ++++++++++++------ 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/openstack/networking/v2/extensions/fwaas_v2/groups/requests.go b/openstack/networking/v2/extensions/fwaas_v2/groups/requests.go index 9b12c62842..856e21548f 100644 --- a/openstack/networking/v2/extensions/fwaas_v2/groups/requests.go +++ b/openstack/networking/v2/extensions/fwaas_v2/groups/requests.go @@ -69,7 +69,8 @@ func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { // Get retrieves a particular firewall group based on its unique ID. func Get(ctx context.Context, c *gophercloud.ServiceClient, id string) (r GetResult) { - _, r.Err = c.Get(ctx, resourceURL(c, id), &r.Body, nil) + resp, err := c.Get(ctx, resourceURL(c, id), &r.Body, nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return } @@ -107,7 +108,8 @@ func Create(ctx context.Context, c *gophercloud.ServiceClient, opts CreateOptsBu r.Err = err return } - _, r.Err = c.Post(ctx, rootURL(c), b, &r.Body, nil) + resp, err := c.Post(ctx, rootURL(c), b, &r.Body, nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return } @@ -142,9 +144,10 @@ func Update(ctx context.Context, c *gophercloud.ServiceClient, id string, opts U r.Err = err return } - _, r.Err = c.Put(ctx, resourceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{ + resp, err := c.Put(ctx, resourceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{ OkCodes: []int{200}, }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return } @@ -165,9 +168,10 @@ func RemoveIngressPolicy(ctx context.Context, c *gophercloud.ServiceClient, id s r.Err = err return } - _, r.Err = c.Put(ctx, resourceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{ + resp, err := c.Put(ctx, resourceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{ OkCodes: []int{200}, }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return } @@ -181,14 +185,16 @@ func RemoveEgressPolicy(ctx context.Context, c *gophercloud.ServiceClient, id st r.Err = err return } - _, r.Err = c.Put(ctx, resourceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{ + resp, err := c.Put(ctx, resourceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{ OkCodes: []int{200}, }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return } // Delete will permanently delete a particular firewall group based on its unique ID. func Delete(ctx context.Context, c *gophercloud.ServiceClient, id string) (r DeleteResult) { - _, r.Err = c.Delete(ctx, resourceURL(c, id), nil) + resp, err := c.Delete(ctx, resourceURL(c, id), nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return } diff --git a/openstack/networking/v2/extensions/fwaas_v2/policies/requests.go b/openstack/networking/v2/extensions/fwaas_v2/policies/requests.go index 57d25a6726..476360dbb3 100644 --- a/openstack/networking/v2/extensions/fwaas_v2/policies/requests.go +++ b/openstack/networking/v2/extensions/fwaas_v2/policies/requests.go @@ -91,13 +91,15 @@ func Create(ctx context.Context, c *gophercloud.ServiceClient, opts CreateOptsBu r.Err = err return } - _, r.Err = c.Post(ctx, rootURL(c), b, &r.Body, nil) + resp, err := c.Post(ctx, rootURL(c), b, &r.Body, nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return } // Get retrieves a particular firewall policy based on its unique ID. func Get(ctx context.Context, c *gophercloud.ServiceClient, id string) (r GetResult) { - _, r.Err = c.Get(ctx, resourceURL(c, id), &r.Body, nil) + resp, err := c.Get(ctx, resourceURL(c, id), &r.Body, nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return } @@ -130,15 +132,17 @@ func Update(ctx context.Context, c *gophercloud.ServiceClient, id string, opts U r.Err = err return } - _, r.Err = c.Put(ctx, resourceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{ + resp, err := c.Put(ctx, resourceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{ OkCodes: []int{200}, }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return } // Delete will permanently delete a particular firewall policy based on its unique ID. func Delete(ctx context.Context, c *gophercloud.ServiceClient, id string) (r DeleteResult) { - _, r.Err = c.Delete(ctx, resourceURL(c, id), nil) + resp, err := c.Delete(ctx, resourceURL(c, id), nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return } @@ -162,16 +166,18 @@ func InsertRule(ctx context.Context, c *gophercloud.ServiceClient, id string, op r.Err = err return } - _, r.Err = c.Put(ctx, insertURL(c, id), b, &r.Body, &gophercloud.RequestOpts{ + resp, err := c.Put(ctx, insertURL(c, id), b, &r.Body, &gophercloud.RequestOpts{ OkCodes: []int{200}, }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return } func RemoveRule(ctx context.Context, c *gophercloud.ServiceClient, id, ruleID string) (r RemoveRuleResult) { b := map[string]any{"firewall_rule_id": ruleID} - _, r.Err = c.Put(ctx, removeURL(c, id), b, &r.Body, &gophercloud.RequestOpts{ + resp, err := c.Put(ctx, removeURL(c, id), b, &r.Body, &gophercloud.RequestOpts{ OkCodes: []int{200}, }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return } From 0948e1ad71e855326e0828d3029be156ac339778 Mon Sep 17 00:00:00 2001 From: kayrus Date: Fri, 27 Sep 2024 16:30:28 +0200 Subject: [PATCH 037/429] [octavia] add an ability to filter flavors and flavorprofiles --- .../v2/flavorprofiles/requests.go | 4 ++ openstack/loadbalancer/v2/flavors/requests.go | 6 +++ .../v2/flavors/testing/requests_test.go | 47 +++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/openstack/loadbalancer/v2/flavorprofiles/requests.go b/openstack/loadbalancer/v2/flavorprofiles/requests.go index 594b79739a..e51b9d99e6 100644 --- a/openstack/loadbalancer/v2/flavorprofiles/requests.go +++ b/openstack/loadbalancer/v2/flavorprofiles/requests.go @@ -15,6 +15,10 @@ type ListOptsBuilder interface { // ListOpts allows to manage the output of the request. type ListOpts struct { + // The name of the flavor profile to filter by. + Name string `q:"name"` + // The provider name of the flavor profile to filter by. + ProviderName string `q:"provider_name"` // The fields that you want the server to return Fields []string `q:"fields"` } diff --git a/openstack/loadbalancer/v2/flavors/requests.go b/openstack/loadbalancer/v2/flavors/requests.go index 6c4859116c..cba77c1d78 100644 --- a/openstack/loadbalancer/v2/flavors/requests.go +++ b/openstack/loadbalancer/v2/flavors/requests.go @@ -15,6 +15,12 @@ type ListOptsBuilder interface { // ListOpts allows to manage the output of the request. type ListOpts struct { + // The name of the flavor to filter by. + Name string `q:"name"` + // The flavor profile id to filter by. + FlavorProfileId string `q:"flavor_profile_id"` + // The enabled status of the flavor to filter by. + Enabled *bool `q:"enabled"` // The fields that you want the server to return Fields []string `q:"fields"` } diff --git a/openstack/loadbalancer/v2/flavors/testing/requests_test.go b/openstack/loadbalancer/v2/flavors/testing/requests_test.go index 14a74dbe45..fd668a2134 100644 --- a/openstack/loadbalancer/v2/flavors/testing/requests_test.go +++ b/openstack/loadbalancer/v2/flavors/testing/requests_test.go @@ -2,6 +2,8 @@ package testing import ( "context" + "fmt" + "net/http" "testing" "github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/flavors" @@ -9,6 +11,7 @@ import ( fake "github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/testhelper" th "github.com/gophercloud/gophercloud/v2/testhelper" + "github.com/gophercloud/gophercloud/v2/testhelper/client" ) func TestListFlavors(t *testing.T) { @@ -41,6 +44,50 @@ func TestListFlavors(t *testing.T) { } } +func TestListFlavorsEnabled(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + + func() { + testCases := []string{ + "true", + "false", + "", + } + + cases := 0 + th.Mux.HandleFunc("/v2.0/lbaas/flavors", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + if err := r.ParseForm(); err != nil { + t.Errorf("Failed to parse request form %v", err) + } + enabled := r.Form.Get("enabled") + if enabled != testCases[cases] { + t.Errorf("Expected enabled=%s got %q", testCases[cases], enabled) + } + cases++ + fmt.Fprintf(w, `{"flavorprofiles":[]}`) + }) + }() + + var nilBool *bool + enabled := true + filters := []*bool{ + &enabled, + new(bool), + nilBool, + } + for _, filter := range filters { + allPages, err := flavors.List(fake.ServiceClient(), flavors.ListOpts{Enabled: filter}).AllPages(context.TODO()) + th.AssertNoErr(t, err) + _, err = flavors.ExtractFlavors(allPages) + th.AssertNoErr(t, err) + } +} + func TestListAllFlavors(t *testing.T) { th.SetupHTTP() defer th.TeardownHTTP() From b236ccd5c490d6a3cd9a64cc1b9b029c4a2a69d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?p=C3=BDrus?= Date: Fri, 4 Oct 2024 09:05:35 +0200 Subject: [PATCH 038/429] Update openstack/loadbalancer/v2/flavors/requests.go Co-authored-by: Emilien Macchi --- openstack/loadbalancer/v2/flavors/requests.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openstack/loadbalancer/v2/flavors/requests.go b/openstack/loadbalancer/v2/flavors/requests.go index cba77c1d78..710a6edf5b 100644 --- a/openstack/loadbalancer/v2/flavors/requests.go +++ b/openstack/loadbalancer/v2/flavors/requests.go @@ -18,7 +18,7 @@ type ListOpts struct { // The name of the flavor to filter by. Name string `q:"name"` // The flavor profile id to filter by. - FlavorProfileId string `q:"flavor_profile_id"` + FlavorProfileID string `q:"flavor_profile_id"` // The enabled status of the flavor to filter by. Enabled *bool `q:"enabled"` // The fields that you want the server to return From a814c3be18fe1f99eaf494641a47d1929ec05956 Mon Sep 17 00:00:00 2001 From: Pierre Prinetti Date: Fri, 4 Oct 2024 12:09:02 +0200 Subject: [PATCH 039/429] compute: Fix expected and actual test results Our test convenience function `AssertEquals` accept the expected value first, then the actual value. Many tests in Compute were using it the other way around, thus potentially returning confusing error messages. --- .../compute/v2/attachinterfaces_test.go | 2 +- .../compute/v2/availabilityzones_test.go | 4 +- .../compute/v2/bootfromvolume_test.go | 20 ++--- .../openstack/compute/v2/compute.go | 84 +++++++++---------- .../openstack/compute/v2/extension_test.go | 4 +- .../openstack/compute/v2/flavors_test.go | 34 ++++---- .../compute/v2/instance_actions_test.go | 6 +- .../openstack/compute/v2/keypairs_test.go | 6 +- .../openstack/compute/v2/limits_test.go | 4 +- .../openstack/compute/v2/quotaset_test.go | 2 +- .../openstack/compute/v2/secgroup_test.go | 12 +-- .../openstack/compute/v2/servergroup_test.go | 4 +- .../openstack/compute/v2/servers_test.go | 40 ++++----- .../openstack/compute/v2/services_test.go | 6 +- .../openstack/compute/v2/volumeattach_test.go | 2 +- 15 files changed, 115 insertions(+), 115 deletions(-) diff --git a/internal/acceptance/openstack/compute/v2/attachinterfaces_test.go b/internal/acceptance/openstack/compute/v2/attachinterfaces_test.go index cf9b1a973e..95ad0ebf2d 100644 --- a/internal/acceptance/openstack/compute/v2/attachinterfaces_test.go +++ b/internal/acceptance/openstack/compute/v2/attachinterfaces_test.go @@ -48,5 +48,5 @@ func TestAttachDetachInterface(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } diff --git a/internal/acceptance/openstack/compute/v2/availabilityzones_test.go b/internal/acceptance/openstack/compute/v2/availabilityzones_test.go index b3af24b0a1..3b37db49b0 100644 --- a/internal/acceptance/openstack/compute/v2/availabilityzones_test.go +++ b/internal/acceptance/openstack/compute/v2/availabilityzones_test.go @@ -31,7 +31,7 @@ func TestAvailabilityZonesList(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestAvailabilityZonesListDetail(t *testing.T) { @@ -55,5 +55,5 @@ func TestAvailabilityZonesListDetail(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } diff --git a/internal/acceptance/openstack/compute/v2/bootfromvolume_test.go b/internal/acceptance/openstack/compute/v2/bootfromvolume_test.go index 5bf7f75e13..4b7082ab3a 100644 --- a/internal/acceptance/openstack/compute/v2/bootfromvolume_test.go +++ b/internal/acceptance/openstack/compute/v2/bootfromvolume_test.go @@ -39,7 +39,7 @@ func TestBootFromImage(t *testing.T) { tools.PrintResource(t, server) - th.AssertEquals(t, server.Image["id"], choices.ImageID) + th.AssertEquals(t, choices.ImageID, server.Image["id"]) } func TestBootFromNewVolume(t *testing.T) { @@ -80,13 +80,13 @@ func TestBootFromNewVolume(t *testing.T) { tools.PrintResource(t, server) tools.PrintResource(t, attachments) attachmentTag := *attachments[0].Tag - th.AssertEquals(t, attachmentTag, tagName) + th.AssertEquals(t, tagName, attachmentTag) if server.Image != nil { t.Fatalf("server image should be nil") } - th.AssertEquals(t, len(attachments), 1) + th.AssertEquals(t, 1, len(attachments)) // TODO: volumes_attached extension } @@ -131,8 +131,8 @@ func TestBootFromExistingVolume(t *testing.T) { t.Fatalf("server image should be nil") } - th.AssertEquals(t, len(attachments), 1) - th.AssertEquals(t, attachments[0].VolumeID, volume.ID) + th.AssertEquals(t, 1, len(attachments)) + th.AssertEquals(t, volume.ID, attachments[0].VolumeID) // TODO: volumes_attached extension } @@ -218,8 +218,8 @@ func TestAttachNewVolume(t *testing.T) { tools.PrintResource(t, server) tools.PrintResource(t, attachments) - th.AssertEquals(t, server.Image["id"], choices.ImageID) - th.AssertEquals(t, len(attachments), 1) + th.AssertEquals(t, choices.ImageID, server.Image["id"]) + th.AssertEquals(t, 1, len(attachments)) // TODO: volumes_attached extension } @@ -269,9 +269,9 @@ func TestAttachExistingVolume(t *testing.T) { tools.PrintResource(t, server) tools.PrintResource(t, attachments) - th.AssertEquals(t, server.Image["id"], choices.ImageID) - th.AssertEquals(t, len(attachments), 1) - th.AssertEquals(t, attachments[0].VolumeID, volume.ID) + th.AssertEquals(t, choices.ImageID, server.Image["id"]) + th.AssertEquals(t, 1, len(attachments)) + th.AssertEquals(t, volume.ID, attachments[0].VolumeID) // TODO: volumes_attached extension } diff --git a/internal/acceptance/openstack/compute/v2/compute.go b/internal/acceptance/openstack/compute/v2/compute.go index 513344082f..4a5ec655a2 100644 --- a/internal/acceptance/openstack/compute/v2/compute.go +++ b/internal/acceptance/openstack/compute/v2/compute.go @@ -84,8 +84,8 @@ func CreateAggregate(t *testing.T, client *gophercloud.ServiceClient) (*aggregat return nil, err } - th.AssertEquals(t, aggregate.Name, aggregateName) - th.AssertEquals(t, aggregate.AvailabilityZone, availabilityZone) + th.AssertEquals(t, aggregateName, aggregate.Name) + th.AssertEquals(t, availabilityZone, aggregate.AvailabilityZone) return aggregate, nil } @@ -137,7 +137,7 @@ func CreateBootableVolumeServer(t *testing.T, client *gophercloud.ServiceClient, return nil, err } - th.AssertEquals(t, newServer.Name, name) + th.AssertEquals(t, name, newServer.Name) return newServer, nil } @@ -169,12 +169,12 @@ func CreateFlavor(t *testing.T, client *gophercloud.ServiceClient) (*flavors.Fla t.Logf("Successfully created flavor %s", flavor.ID) - th.AssertEquals(t, flavor.Name, flavorName) - th.AssertEquals(t, flavor.RAM, 1) - th.AssertEquals(t, flavor.Disk, 1) - th.AssertEquals(t, flavor.VCPUs, 1) - th.AssertEquals(t, flavor.IsPublic, true) - th.AssertEquals(t, flavor.Description, flavorDescription) + th.AssertEquals(t, flavorName, flavor.Name) + th.AssertEquals(t, 1, flavor.RAM) + th.AssertEquals(t, 1, flavor.Disk) + th.AssertEquals(t, 1, flavor.VCPUs) + th.AssertEquals(t, true, flavor.IsPublic) + th.AssertEquals(t, flavorDescription, flavor.Description) return flavor, nil } @@ -213,7 +213,7 @@ func CreateKeyPair(t *testing.T, client *gophercloud.ServiceClient) (*keypairs.K t.Logf("Created keypair: %s", keyPairName) - th.AssertEquals(t, keyPair.Name, keyPairName) + th.AssertEquals(t, keyPairName, keyPair.Name) return keyPair, nil } @@ -263,9 +263,9 @@ func CreateMultiEphemeralServer(t *testing.T, client *gophercloud.ServiceClient, if err != nil { return server, err } - th.AssertEquals(t, newServer.Name, name) - th.AssertEquals(t, newServer.Flavor["id"], choices.FlavorID) - th.AssertEquals(t, newServer.Image["id"], choices.ImageID) + th.AssertEquals(t, name, newServer.Name) + th.AssertEquals(t, choices.FlavorID, newServer.Flavor["id"]) + th.AssertEquals(t, choices.ImageID, newServer.Image["id"]) return newServer, nil } @@ -292,11 +292,11 @@ func CreatePrivateFlavor(t *testing.T, client *gophercloud.ServiceClient) (*flav t.Logf("Successfully created flavor %s", flavor.ID) - th.AssertEquals(t, flavor.Name, flavorName) - th.AssertEquals(t, flavor.RAM, 1) - th.AssertEquals(t, flavor.Disk, 1) - th.AssertEquals(t, flavor.VCPUs, 1) - th.AssertEquals(t, flavor.IsPublic, false) + th.AssertEquals(t, flavorName, flavor.Name) + th.AssertEquals(t, 1, flavor.RAM) + th.AssertEquals(t, 1, flavor.Disk) + th.AssertEquals(t, 1, flavor.VCPUs) + th.AssertEquals(t, false, flavor.IsPublic) return flavor, nil } @@ -318,7 +318,7 @@ func CreateSecurityGroup(t *testing.T, client *gophercloud.ServiceClient) (*secg t.Logf("Created security group: %s", securityGroup.ID) - th.AssertEquals(t, securityGroup.Name, name) + th.AssertEquals(t, name, securityGroup.Name) return securityGroup, nil } @@ -344,9 +344,9 @@ func CreateSecurityGroupRule(t *testing.T, client *gophercloud.ServiceClient, se t.Logf("Created security group rule: %s", rule.ID) - th.AssertEquals(t, rule.FromPort, fromPort) - th.AssertEquals(t, rule.ToPort, toPort) - th.AssertEquals(t, rule.ParentGroupID, securityGroupID) + th.AssertEquals(t, fromPort, rule.FromPort) + th.AssertEquals(t, toPort, rule.ToPort) + th.AssertEquals(t, securityGroupID, rule.ParentGroupID) return rule, nil } @@ -403,9 +403,9 @@ func CreateServer(t *testing.T, client *gophercloud.ServiceClient) (*servers.Ser return nil, err } - th.AssertEquals(t, newServer.Name, name) - th.AssertEquals(t, newServer.Flavor["id"], choices.FlavorID) - th.AssertEquals(t, newServer.Image["id"], choices.ImageID) + th.AssertEquals(t, name, newServer.Name) + th.AssertEquals(t, choices.FlavorID, newServer.Flavor["id"]) + th.AssertEquals(t, choices.ImageID, newServer.Image["id"]) return newServer, nil } @@ -457,8 +457,8 @@ func CreateMicroversionServer(t *testing.T, client *gophercloud.ServiceClient) ( return nil, err } - th.AssertEquals(t, newServer.Name, name) - th.AssertEquals(t, newServer.Image["id"], choices.ImageID) + th.AssertEquals(t, name, newServer.Name) + th.AssertEquals(t, choices.ImageID, newServer.Image["id"]) return newServer, nil } @@ -560,8 +560,8 @@ func CreateServerWithTags(t *testing.T, client *gophercloud.ServiceClient, netwo newServer, err := res.Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, newServer.Name, name) - th.AssertDeepEquals(t, *newServer.Tags, []string{"tag1", "tag2"}) + th.AssertEquals(t, name, newServer.Name) + th.AssertDeepEquals(t, []string{"tag1", "tag2"}, *newServer.Tags) return newServer, nil } @@ -584,7 +584,7 @@ func CreateServerGroup(t *testing.T, client *gophercloud.ServiceClient, policy s t.Logf("Successfully created server group %s", name) - th.AssertEquals(t, sg.Name, name) + th.AssertEquals(t, name, sg.Name) return sg, nil } @@ -612,7 +612,7 @@ func CreateServerGroupMicroversion(t *testing.T, client *gophercloud.ServiceClie t.Logf("Successfully created server group %s", name) - th.AssertEquals(t, sg.Name, name) + th.AssertEquals(t, name, sg.Name) return sg, nil } @@ -662,9 +662,9 @@ func CreateServerInServerGroup(t *testing.T, client *gophercloud.ServiceClient, return nil, err } - th.AssertEquals(t, newServer.Name, name) - th.AssertEquals(t, newServer.Flavor["id"], choices.FlavorID) - th.AssertEquals(t, newServer.Image["id"], choices.ImageID) + th.AssertEquals(t, name, newServer.Name) + th.AssertEquals(t, choices.FlavorID, newServer.Flavor["id"]) + th.AssertEquals(t, choices.ImageID, newServer.Image["id"]) return newServer, nil } @@ -711,9 +711,9 @@ func CreateServerWithPublicKey(t *testing.T, client *gophercloud.ServiceClient, return nil, err } - th.AssertEquals(t, newServer.Name, name) - th.AssertEquals(t, newServer.Flavor["id"], choices.FlavorID) - th.AssertEquals(t, newServer.Image["id"], choices.ImageID) + th.AssertEquals(t, name, newServer.Name) + th.AssertEquals(t, choices.FlavorID, newServer.Flavor["id"]) + th.AssertEquals(t, choices.ImageID, newServer.Image["id"]) return newServer, nil } @@ -910,8 +910,8 @@ func ImportPublicKey(t *testing.T, client *gophercloud.ServiceClient, publicKey t.Logf("Created keypair: %s", keyPairName) - th.AssertEquals(t, keyPair.Name, keyPairName) - th.AssertEquals(t, keyPair.PublicKey, publicKey) + th.AssertEquals(t, keyPairName, keyPair.Name) + th.AssertEquals(t, publicKey, keyPair.PublicKey) return keyPair, nil } @@ -1070,9 +1070,9 @@ func CreateServerNoNetwork(t *testing.T, client *gophercloud.ServiceClient) (*se return nil, err } - th.AssertEquals(t, newServer.Name, name) - th.AssertEquals(t, newServer.Flavor["id"], choices.FlavorID) - th.AssertEquals(t, newServer.Image["id"], choices.ImageID) + th.AssertEquals(t, name, newServer.Name) + th.AssertEquals(t, choices.FlavorID, newServer.Flavor["id"]) + th.AssertEquals(t, choices.ImageID, newServer.Image["id"]) return newServer, nil } diff --git a/internal/acceptance/openstack/compute/v2/extension_test.go b/internal/acceptance/openstack/compute/v2/extension_test.go index 0339b251fb..8040282289 100644 --- a/internal/acceptance/openstack/compute/v2/extension_test.go +++ b/internal/acceptance/openstack/compute/v2/extension_test.go @@ -31,7 +31,7 @@ func TestExtensionsList(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestExtensionsGet(t *testing.T) { @@ -43,5 +43,5 @@ func TestExtensionsGet(t *testing.T) { tools.PrintResource(t, extension) - th.AssertEquals(t, extension.Name, "AdminActions") + th.AssertEquals(t, "AdminActions", extension.Name) } diff --git a/internal/acceptance/openstack/compute/v2/flavors_test.go b/internal/acceptance/openstack/compute/v2/flavors_test.go index cb6bd319a1..412149adfe 100644 --- a/internal/acceptance/openstack/compute/v2/flavors_test.go +++ b/internal/acceptance/openstack/compute/v2/flavors_test.go @@ -35,7 +35,7 @@ func TestFlavorsList(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestFlavorsAccessTypeList(t *testing.T) { @@ -74,7 +74,7 @@ func TestFlavorsGet(t *testing.T) { tools.PrintResource(t, flavor) - th.AssertEquals(t, flavor.ID, choices.FlavorID) + th.AssertEquals(t, choices.FlavorID, flavor.ID) } func TestFlavorExtraSpecsGet(t *testing.T) { @@ -103,9 +103,9 @@ func TestFlavorExtraSpecsGet(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, flavor) - th.AssertEquals(t, len(flavor.ExtraSpecs), 2) - th.AssertEquals(t, flavor.ExtraSpecs["hw:cpu_policy"], "CPU-POLICY") - th.AssertEquals(t, flavor.ExtraSpecs["hw:cpu_thread_policy"], "CPU-THREAD-POLICY") + th.AssertEquals(t, 2, len(flavor.ExtraSpecs)) + th.AssertEquals(t, "CPU-POLICY", flavor.ExtraSpecs["hw:cpu_policy"]) + th.AssertEquals(t, "CPU-THREAD-POLICY", flavor.ExtraSpecs["hw:cpu_thread_policy"]) } func TestFlavorsCreateDelete(t *testing.T) { @@ -140,7 +140,7 @@ func TestFlavorsCreateUpdateDelete(t *testing.T) { flavor, err = flavors.Update(context.TODO(), client, flavor.ID, updateOpts).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, flavor.Description, newFlavorDescription) + th.AssertEquals(t, newFlavorDescription, flavor.Description) tools.PrintResource(t, flavor) } @@ -161,7 +161,7 @@ func TestFlavorsAccessesList(t *testing.T) { allAccesses, err := flavors.ExtractAccesses(allPages) th.AssertNoErr(t, err) - th.AssertEquals(t, len(allAccesses), 0) + th.AssertEquals(t, 0, len(allAccesses)) } func TestFlavorsAccessCRUD(t *testing.T) { @@ -188,9 +188,9 @@ func TestFlavorsAccessCRUD(t *testing.T) { accessList, err := flavors.AddAccess(context.TODO(), client, flavor.ID, addAccessOpts).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, len(accessList), 1) - th.AssertEquals(t, accessList[0].TenantID, project.ID) - th.AssertEquals(t, accessList[0].FlavorID, flavor.ID) + th.AssertEquals(t, 1, len(accessList)) + th.AssertEquals(t, project.ID, accessList[0].TenantID) + th.AssertEquals(t, flavor.ID, accessList[0].FlavorID) for _, access := range accessList { tools.PrintResource(t, access) @@ -203,7 +203,7 @@ func TestFlavorsAccessCRUD(t *testing.T) { accessList, err = flavors.RemoveAccess(context.TODO(), client, flavor.ID, removeAccessOpts).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, len(accessList), 0) + th.AssertEquals(t, 0, len(accessList)) } func TestFlavorsExtraSpecsCRUD(t *testing.T) { @@ -225,9 +225,9 @@ func TestFlavorsExtraSpecsCRUD(t *testing.T) { tools.PrintResource(t, createdExtraSpecs) - th.AssertEquals(t, len(createdExtraSpecs), 2) - th.AssertEquals(t, createdExtraSpecs["hw:cpu_policy"], "CPU-POLICY") - th.AssertEquals(t, createdExtraSpecs["hw:cpu_thread_policy"], "CPU-THREAD-POLICY") + th.AssertEquals(t, 2, len(createdExtraSpecs)) + th.AssertEquals(t, "CPU-POLICY", createdExtraSpecs["hw:cpu_policy"]) + th.AssertEquals(t, "CPU-THREAD-POLICY", createdExtraSpecs["hw:cpu_thread_policy"]) err = flavors.DeleteExtraSpec(context.TODO(), client, flavor.ID, "hw:cpu_policy").ExtractErr() th.AssertNoErr(t, err) @@ -245,13 +245,13 @@ func TestFlavorsExtraSpecsCRUD(t *testing.T) { tools.PrintResource(t, allExtraSpecs) - th.AssertEquals(t, len(allExtraSpecs), 1) - th.AssertEquals(t, allExtraSpecs["hw:cpu_thread_policy"], "CPU-THREAD-POLICY-BETTER") + th.AssertEquals(t, 1, len(allExtraSpecs)) + th.AssertEquals(t, "CPU-THREAD-POLICY-BETTER", allExtraSpecs["hw:cpu_thread_policy"]) spec, err := flavors.GetExtraSpec(context.TODO(), client, flavor.ID, "hw:cpu_thread_policy").Extract() th.AssertNoErr(t, err) tools.PrintResource(t, spec) - th.AssertEquals(t, spec["hw:cpu_thread_policy"], "CPU-THREAD-POLICY-BETTER") + th.AssertEquals(t, "CPU-THREAD-POLICY-BETTER", spec["hw:cpu_thread_policy"]) } diff --git a/internal/acceptance/openstack/compute/v2/instance_actions_test.go b/internal/acceptance/openstack/compute/v2/instance_actions_test.go index fb43cd72d6..01dd9fc72c 100644 --- a/internal/acceptance/openstack/compute/v2/instance_actions_test.go +++ b/internal/acceptance/openstack/compute/v2/instance_actions_test.go @@ -39,7 +39,7 @@ func TestInstanceActions(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestInstanceActionsMicroversions(t *testing.T) { @@ -88,7 +88,7 @@ func TestInstanceActionsMicroversions(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) listOpts = instanceactions.ListOpts{ Limit: 1, @@ -101,5 +101,5 @@ func TestInstanceActionsMicroversions(t *testing.T) { allActions, err = instanceactions.ExtractInstanceActions(allPages) th.AssertNoErr(t, err) - th.AssertEquals(t, len(allActions), 0) + th.AssertEquals(t, 0, len(allActions)) } diff --git a/internal/acceptance/openstack/compute/v2/keypairs_test.go b/internal/acceptance/openstack/compute/v2/keypairs_test.go index f3a0ac7e32..09d28f24f5 100644 --- a/internal/acceptance/openstack/compute/v2/keypairs_test.go +++ b/internal/acceptance/openstack/compute/v2/keypairs_test.go @@ -57,7 +57,7 @@ func TestKeyPairsCreateDelete(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestKeyPairsImportPublicKey(t *testing.T) { @@ -94,7 +94,7 @@ func TestKeyPairsServerCreateWithKey(t *testing.T) { server, err = servers.Get(context.TODO(), client, server.ID).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, server.KeyName, keyPair.Name) + th.AssertEquals(t, keyPair.Name, server.KeyName) } func TestKeyPairsCreateDeleteByID(t *testing.T) { @@ -146,7 +146,7 @@ func TestKeyPairsCreateDeleteByID(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) deleteOpts := keypairs.DeleteOpts{ UserID: user.ID, diff --git a/internal/acceptance/openstack/compute/v2/limits_test.go b/internal/acceptance/openstack/compute/v2/limits_test.go index 55ef2854f2..a4240ee5e0 100644 --- a/internal/acceptance/openstack/compute/v2/limits_test.go +++ b/internal/acceptance/openstack/compute/v2/limits_test.go @@ -22,7 +22,7 @@ func TestLimits(t *testing.T) { tools.PrintResource(t, limits) - th.AssertEquals(t, limits.Absolute.MaxPersonalitySize, 10240) + th.AssertEquals(t, 10240, limits.Absolute.MaxPersonalitySize) } func TestLimitsForTenant(t *testing.T) { @@ -47,5 +47,5 @@ func TestLimitsForTenant(t *testing.T) { tools.PrintResource(t, limits) - th.AssertEquals(t, limits.Absolute.MaxPersonalitySize, 10240) + th.AssertEquals(t, 10240, limits.Absolute.MaxPersonalitySize) } diff --git a/internal/acceptance/openstack/compute/v2/quotaset_test.go b/internal/acceptance/openstack/compute/v2/quotaset_test.go index 78ebbae2f0..53d94b538e 100644 --- a/internal/acceptance/openstack/compute/v2/quotaset_test.go +++ b/internal/acceptance/openstack/compute/v2/quotaset_test.go @@ -31,7 +31,7 @@ func TestQuotasetGet(t *testing.T) { tools.PrintResource(t, quotaSet) - th.AssertEquals(t, quotaSet.FixedIPs, -1) + th.AssertEquals(t, -1, quotaSet.FixedIPs) } func getProjectID(t *testing.T, client *gophercloud.ServiceClient) (string, error) { diff --git a/internal/acceptance/openstack/compute/v2/secgroup_test.go b/internal/acceptance/openstack/compute/v2/secgroup_test.go index 0809bb0dda..dd6b6dd85e 100644 --- a/internal/acceptance/openstack/compute/v2/secgroup_test.go +++ b/internal/acceptance/openstack/compute/v2/secgroup_test.go @@ -32,7 +32,7 @@ func TestSecGroupsList(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestSecGroupsCRUD(t *testing.T) { @@ -58,8 +58,8 @@ func TestSecGroupsCRUD(t *testing.T) { t.Logf("Updated %s's name to %s", updatedSecurityGroup.ID, updatedSecurityGroup.Name) - th.AssertEquals(t, updatedSecurityGroup.Name, newName) - th.AssertEquals(t, updatedSecurityGroup.Description, description) + th.AssertEquals(t, newName, updatedSecurityGroup.Name) + th.AssertEquals(t, description, updatedSecurityGroup.Description) } func TestSecGroupsRuleCreate(t *testing.T) { @@ -83,7 +83,7 @@ func TestSecGroupsRuleCreate(t *testing.T) { tools.PrintResource(t, newSecurityGroup) - th.AssertEquals(t, len(newSecurityGroup.Rules), 1) + th.AssertEquals(t, 1, len(newSecurityGroup.Rules)) } func TestSecGroupsAddGroupToServer(t *testing.T) { @@ -120,7 +120,7 @@ func TestSecGroupsAddGroupToServer(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) t.Logf("Removing group %s from server %s", securityGroup.ID, server.ID) err = secgroups.RemoveServer(context.TODO(), client, server.ID, securityGroup.Name).ExtractErr() @@ -139,5 +139,5 @@ func TestSecGroupsAddGroupToServer(t *testing.T) { } } - th.AssertEquals(t, found, false) + th.AssertEquals(t, false, found) } diff --git a/internal/acceptance/openstack/compute/v2/servergroup_test.go b/internal/acceptance/openstack/compute/v2/servergroup_test.go index 8d23ea8135..09d351a7b4 100644 --- a/internal/acceptance/openstack/compute/v2/servergroup_test.go +++ b/internal/acceptance/openstack/compute/v2/servergroup_test.go @@ -41,7 +41,7 @@ func TestServergroupsCreateDelete(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestServergroupsAffinityPolicy(t *testing.T) { @@ -100,5 +100,5 @@ func TestServergroupsMicroversionCreateDelete(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } diff --git a/internal/acceptance/openstack/compute/v2/servers_test.go b/internal/acceptance/openstack/compute/v2/servers_test.go index 9aa8133de9..5934805ba2 100644 --- a/internal/acceptance/openstack/compute/v2/servers_test.go +++ b/internal/acceptance/openstack/compute/v2/servers_test.go @@ -45,7 +45,7 @@ func TestServersCreateDestroy(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) allAddressPages, err := servers.ListAddresses(client, server.ID).AllPages(context.TODO()) th.AssertNoErr(t, err) @@ -93,12 +93,12 @@ func TestServersWithExtensionsCreateDestroy(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, created) - th.AssertEquals(t, created.AvailabilityZone, "nova") - th.AssertEquals(t, int(created.PowerState), servers.RUNNING) - th.AssertEquals(t, created.TaskState, "") - th.AssertEquals(t, created.VmState, "active") - th.AssertEquals(t, created.LaunchedAt.IsZero(), false) - th.AssertEquals(t, created.TerminatedAt.IsZero(), true) + th.AssertEquals(t, "nova", created.AvailabilityZone) + th.AssertEquals(t, servers.RUNNING, int(created.PowerState)) + th.AssertEquals(t, "", created.TaskState) + th.AssertEquals(t, "active", created.VmState) + th.AssertEquals(t, false, created.LaunchedAt.IsZero()) + th.AssertEquals(t, true, created.TerminatedAt.IsZero()) } func TestServersWithoutImageRef(t *testing.T) { @@ -139,7 +139,7 @@ func TestServersUpdate(t *testing.T) { updated, err := servers.Update(context.TODO(), client, server.ID, updateOpts).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, updated.ID, server.ID) + th.AssertEquals(t, server.ID, updated.ID) err = tools.WaitFor(func(ctx context.Context) (bool, error) { latest, err := servers.Get(ctx, client, updated.ID).Extract() @@ -307,7 +307,7 @@ func TestServersActionRebuild(t *testing.T) { rebuilt, err := servers.Rebuild(context.TODO(), client, server.ID, rebuildOpts).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, rebuilt.ID, server.ID) + th.AssertEquals(t, server.ID, rebuilt.ID) if err = WaitForComputeStatus(client, rebuilt, "REBUILD"); err != nil { t.Fatal(err) @@ -347,7 +347,7 @@ func TestServersActionResizeConfirm(t *testing.T) { server, err = servers.Get(context.TODO(), client, server.ID).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, server.Flavor["id"], choices.FlavorIDResize) + th.AssertEquals(t, choices.FlavorIDResize, server.Flavor["id"]) } func TestServersActionResizeRevert(t *testing.T) { @@ -379,7 +379,7 @@ func TestServersActionResizeRevert(t *testing.T) { server, err = servers.Get(context.TODO(), client, server.ID).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, server.Flavor["id"], choices.FlavorID) + th.AssertEquals(t, choices.FlavorID, server.Flavor["id"]) } func TestServersActionPause(t *testing.T) { @@ -447,7 +447,7 @@ func TestServersActionLock(t *testing.T) { t.Logf("Attempting to delete locked server %s", server.ID) err = servers.Delete(context.TODO(), client, server.ID).ExtractErr() - th.AssertEquals(t, err != nil, true) + th.AssertEquals(t, true, err != nil) t.Logf("Attempting to unlock server %s", server.ID) err = servers.Unlock(context.TODO(), client, server.ID).ExtractErr() @@ -565,13 +565,13 @@ func TestServersWithExtendedAttributesCreateDestroy(t *testing.T) { t.Logf("Server With Extended Attributes: %#v", created) - th.AssertEquals(t, *created.ReservationID != "", true) - th.AssertEquals(t, *created.LaunchIndex, 0) - th.AssertEquals(t, *created.RAMDiskID == "", true) - th.AssertEquals(t, *created.KernelID == "", true) - th.AssertEquals(t, *created.Hostname != "", true) - th.AssertEquals(t, *created.RootDeviceName != "", true) - th.AssertEquals(t, created.Userdata == nil, true) + th.AssertEquals(t, true, *created.ReservationID != "") + th.AssertEquals(t, 0, *created.LaunchIndex) + th.AssertEquals(t, true, *created.RAMDiskID == "") + th.AssertEquals(t, true, *created.KernelID == "") + th.AssertEquals(t, true, *created.Hostname != "") + th.AssertEquals(t, true, *created.RootDeviceName != "") + th.AssertEquals(t, true, created.Userdata == nil) } func TestServerNoNetworkCreateDestroy(t *testing.T) { @@ -604,7 +604,7 @@ func TestServerNoNetworkCreateDestroy(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) allAddressPages, err := servers.ListAddresses(client, server.ID).AllPages(context.TODO()) th.AssertNoErr(t, err) diff --git a/internal/acceptance/openstack/compute/v2/services_test.go b/internal/acceptance/openstack/compute/v2/services_test.go index 30b1613aa5..7b8d8725b5 100644 --- a/internal/acceptance/openstack/compute/v2/services_test.go +++ b/internal/acceptance/openstack/compute/v2/services_test.go @@ -33,7 +33,7 @@ func TestServicesList(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestServicesListWithOpts(t *testing.T) { @@ -55,12 +55,12 @@ func TestServicesListWithOpts(t *testing.T) { var found bool for _, service := range allServices { tools.PrintResource(t, service) - th.AssertEquals(t, service.Binary, "nova-scheduler") + th.AssertEquals(t, "nova-scheduler", service.Binary) if service.Binary == "nova-scheduler" { found = true } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } diff --git a/internal/acceptance/openstack/compute/v2/volumeattach_test.go b/internal/acceptance/openstack/compute/v2/volumeattach_test.go index d4cce8d700..157f97c4c0 100644 --- a/internal/acceptance/openstack/compute/v2/volumeattach_test.go +++ b/internal/acceptance/openstack/compute/v2/volumeattach_test.go @@ -35,5 +35,5 @@ func TestVolumeAttachAttachment(t *testing.T) { tools.PrintResource(t, volumeAttachment) - th.AssertEquals(t, volumeAttachment.ServerID, server.ID) + th.AssertEquals(t, server.ID, volumeAttachment.ServerID) } From e899b1b8e831a8d661c59e43c9752ec3577fafa5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 09:49:00 +0000 Subject: [PATCH 040/429] build(deps): bump golang.org/x/crypto from 0.27.0 to 0.28.0 Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.27.0 to 0.28.0. - [Commits](https://github.com/golang/crypto/compare/v0.27.0...v0.28.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 0f39082357..8e527ec8e5 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module github.com/gophercloud/gophercloud/v2 go 1.22 require ( - golang.org/x/crypto v0.27.0 + golang.org/x/crypto v0.28.0 gopkg.in/yaml.v2 v2.4.0 ) -require golang.org/x/sys v0.25.0 // indirect +require golang.org/x/sys v0.26.0 // indirect diff --git a/go.sum b/go.sum index 77cbe99406..7cc4cf43b5 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ -golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= -golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= -golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= +golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= From 962a74bd19b967b05c87f59ad669bef6a7b17ed8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 09:53:34 +0000 Subject: [PATCH 041/429] build(deps): bump kiegroup/git-backporting from 4.8.1 to 4.8.2 Bumps [kiegroup/git-backporting](https://github.com/kiegroup/git-backporting) from 4.8.1 to 4.8.2. - [Release notes](https://github.com/kiegroup/git-backporting/releases) - [Changelog](https://github.com/kiegroup/git-backporting/blob/main/CHANGELOG.md) - [Commits](https://github.com/kiegroup/git-backporting/compare/c5d7f0ea567c9f997ba4d15e442ad3204abe2030...c3daf803062a072dc39fe3e1fb892f6b98a7a4e0) --- updated-dependencies: - dependency-name: kiegroup/git-backporting dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/backport.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/backport.yaml b/.github/workflows/backport.yaml index 0071ecba1d..025e1b6bf3 100644 --- a/.github/workflows/backport.yaml +++ b/.github/workflows/backport.yaml @@ -34,7 +34,7 @@ jobs: if: > contains(github.event.pull_request.labels.*.name, 'semver:patch') || contains(github.event.label.name, 'semver:patch') - uses: kiegroup/git-backporting@c5d7f0ea567c9f997ba4d15e442ad3204abe2030 + uses: kiegroup/git-backporting@c3daf803062a072dc39fe3e1fb892f6b98a7a4e0 with: target-branch: v1 pull-request: ${{ github.event.pull_request.url }} @@ -95,7 +95,7 @@ jobs: || contains(github.event.pull_request.labels.*.name, 'semver:minor') || contains(github.event.label.name, 'semver:patch') || contains(github.event.label.name, 'semver:minor') - uses: kiegroup/git-backporting@c5d7f0ea567c9f997ba4d15e442ad3204abe2030 + uses: kiegroup/git-backporting@c3daf803062a072dc39fe3e1fb892f6b98a7a4e0 with: target-branch: v2 pull-request: ${{ github.event.pull_request.url }} From cbb11892042f6436b8f4b200359f11fc5f2acd15 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 10 Oct 2024 09:06:06 +0000 Subject: [PATCH 042/429] build(deps): bump kiegroup/git-backporting from 4.8.2 to 4.8.3 Bumps [kiegroup/git-backporting](https://github.com/kiegroup/git-backporting) from 4.8.2 to 4.8.3. - [Release notes](https://github.com/kiegroup/git-backporting/releases) - [Changelog](https://github.com/kiegroup/git-backporting/blob/main/CHANGELOG.md) - [Commits](https://github.com/kiegroup/git-backporting/compare/c3daf803062a072dc39fe3e1fb892f6b98a7a4e0...a14014e89e9bac5210298eb1c4047f037b359c97) --- updated-dependencies: - dependency-name: kiegroup/git-backporting dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/backport.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/backport.yaml b/.github/workflows/backport.yaml index 025e1b6bf3..1f7d064ca3 100644 --- a/.github/workflows/backport.yaml +++ b/.github/workflows/backport.yaml @@ -34,7 +34,7 @@ jobs: if: > contains(github.event.pull_request.labels.*.name, 'semver:patch') || contains(github.event.label.name, 'semver:patch') - uses: kiegroup/git-backporting@c3daf803062a072dc39fe3e1fb892f6b98a7a4e0 + uses: kiegroup/git-backporting@a14014e89e9bac5210298eb1c4047f037b359c97 with: target-branch: v1 pull-request: ${{ github.event.pull_request.url }} @@ -95,7 +95,7 @@ jobs: || contains(github.event.pull_request.labels.*.name, 'semver:minor') || contains(github.event.label.name, 'semver:patch') || contains(github.event.label.name, 'semver:minor') - uses: kiegroup/git-backporting@c3daf803062a072dc39fe3e1fb892f6b98a7a4e0 + uses: kiegroup/git-backporting@a14014e89e9bac5210298eb1c4047f037b359c97 with: target-branch: v2 pull-request: ${{ github.event.pull_request.url }} From 2b109d77d065c0eac5f3521cd57338a2248c81fe Mon Sep 17 00:00:00 2001 From: kayrus Date: Thu, 10 Oct 2024 18:02:04 +0200 Subject: [PATCH 043/429] [manila] add scheduler_hints to the shares CreateOpts --- .../sharedfilesystems/v2/shares/requests.go | 19 +++++++++++++++++++ .../v2/shares/testing/fixtures_test.go | 10 ++++++++-- .../v2/shares/testing/request_test.go | 12 +++++++++++- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/openstack/sharedfilesystems/v2/shares/requests.go b/openstack/sharedfilesystems/v2/shares/requests.go index d228f6a36c..8c111b4837 100644 --- a/openstack/sharedfilesystems/v2/shares/requests.go +++ b/openstack/sharedfilesystems/v2/shares/requests.go @@ -7,6 +7,22 @@ import ( "github.com/gophercloud/gophercloud/v2/pagination" ) +// SchedulerHints contains options for providing scheduler hints when creating +// a Share. +type SchedulerHints struct { + // DifferentHost will place the share on a different back-end that does not + // host the given shares. + DifferentHost string `json:"different_host,omitempty"` + + // SameHost will place the share on a back-end that hosts the given shares. + SameHost string `json:"same_host,omitempty"` + + // OnlyHost value must be a manage-share service host in + // host@backend#POOL format (admin only). Only available in and beyond + // API version 2.67 + OnlyHost string `json:"only_host,omitempty"` +} + // CreateOptsBuilder allows extensions to add additional parameters to the // Create request. type CreateOptsBuilder interface { @@ -48,6 +64,9 @@ type CreateOpts struct { ConsistencyGroupID string `json:"consistency_group_id,omitempty"` // The availability zone of the share AvailabilityZone string `json:"availability_zone,omitempty"` + // SchedulerHints are hints for the scheduler to select the share backend + // Only available in and beyond API version 2.65 + SchedulerHints *SchedulerHints `json:"scheduler_hints,omitempty"` } // ToShareCreateMap assembles a request body based on the contents of a diff --git a/openstack/sharedfilesystems/v2/shares/testing/fixtures_test.go b/openstack/sharedfilesystems/v2/shares/testing/fixtures_test.go index 89a2c5461e..cfb9e73d2e 100644 --- a/openstack/sharedfilesystems/v2/shares/testing/fixtures_test.go +++ b/openstack/sharedfilesystems/v2/shares/testing/fixtures_test.go @@ -18,7 +18,11 @@ var createRequest = `{ "share": { "name": "my_test_share", "size": 1, - "share_proto": "NFS" + "share_proto": "NFS", + "scheduler_hints": { + "same_host": "e268f4aa-d571-43dd-9ab3-f49ad06ffaef", + "different_host": "e268f4aa-d571-43dd-9ab3-f49ad06ffaef" + } } }` @@ -61,7 +65,9 @@ var createResponse = `{ "is_public": true, "metadata": { "project": "my_app", - "aim": "doc" + "aim": "doc", + "__affinity_same_host": "e268f4aa-d571-43dd-9ab3-f49ad06ffaef", + "__affinity_different_host": "e268f4aa-d571-43dd-9ab3-f49ad06ffaef" }, "id": "011d21e2-fbc3-4e4a-9993-9ea223f73264", "description": "My custom share London" diff --git a/openstack/sharedfilesystems/v2/shares/testing/request_test.go b/openstack/sharedfilesystems/v2/shares/testing/request_test.go index f9af3da84b..396c73a795 100644 --- a/openstack/sharedfilesystems/v2/shares/testing/request_test.go +++ b/openstack/sharedfilesystems/v2/shares/testing/request_test.go @@ -16,13 +16,23 @@ func TestCreate(t *testing.T) { MockCreateResponse(t) - options := &shares.CreateOpts{Size: 1, Name: "my_test_share", ShareProto: "NFS"} + options := &shares.CreateOpts{ + Size: 1, + Name: "my_test_share", + ShareProto: "NFS", + SchedulerHints: &shares.SchedulerHints{ + SameHost: "e268f4aa-d571-43dd-9ab3-f49ad06ffaef", + DifferentHost: "e268f4aa-d571-43dd-9ab3-f49ad06ffaef", + }, + } n, err := shares.Create(context.TODO(), client.ServiceClient(), options).Extract() th.AssertNoErr(t, err) th.AssertEquals(t, n.Name, "my_test_share") th.AssertEquals(t, n.Size, 1) th.AssertEquals(t, n.ShareProto, "NFS") + th.AssertEquals(t, n.Metadata["__affinity_same_host"], "e268f4aa-d571-43dd-9ab3-f49ad06ffaef") + th.AssertEquals(t, n.Metadata["__affinity_different_host"], "e268f4aa-d571-43dd-9ab3-f49ad06ffaef") } func TestUpdate(t *testing.T) { From f8007eedf55a73bcefb69f0da5efe1f555179c67 Mon Sep 17 00:00:00 2001 From: kayrus Date: Wed, 9 Oct 2024 13:51:57 +0200 Subject: [PATCH 044/429] [manila] add share_group_id to share's CreateOpts --- openstack/sharedfilesystems/v2/shares/requests.go | 2 ++ openstack/sharedfilesystems/v2/shares/results.go | 2 ++ 2 files changed, 4 insertions(+) diff --git a/openstack/sharedfilesystems/v2/shares/requests.go b/openstack/sharedfilesystems/v2/shares/requests.go index d228f6a36c..07949b3caa 100644 --- a/openstack/sharedfilesystems/v2/shares/requests.go +++ b/openstack/sharedfilesystems/v2/shares/requests.go @@ -40,6 +40,8 @@ type CreateOpts struct { SnapshotID string `json:"snapshot_id,omitempty"` // Determines whether or not the share is public IsPublic *bool `json:"is_public,omitempty"` + // The UUID of the share group. Available starting from the microversion 2.31 + ShareGroupID string `json:"share_group_id,omitempty"` // Key value pairs of user defined metadata Metadata map[string]string `json:"metadata,omitempty"` // The UUID of the share network to which the share belongs to diff --git a/openstack/sharedfilesystems/v2/shares/results.go b/openstack/sharedfilesystems/v2/shares/results.go index d3fe9d8437..7c1b621327 100644 --- a/openstack/sharedfilesystems/v2/shares/results.go +++ b/openstack/sharedfilesystems/v2/shares/results.go @@ -54,6 +54,8 @@ type Share struct { ShareType string `json:"share_type"` // The name of the share type. ShareTypeName string `json:"share_type_name"` + // The UUID of the share group. Available starting from the microversion 2.31 + ShareGroupID string `json:"share_group_id"` // Size of the share in GB Size int `json:"size"` // UUID of the snapshot from which to create the share From e7b3ff02ec518dc21a7a77c89b20b286b9724b66 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 11 Oct 2024 09:46:44 +0000 Subject: [PATCH 045/429] build(deps): bump thollander/actions-comment-pull-request Bumps [thollander/actions-comment-pull-request](https://github.com/thollander/actions-comment-pull-request) from 2.5.0 to 3.0.0. - [Release notes](https://github.com/thollander/actions-comment-pull-request/releases) - [Commits](https://github.com/thollander/actions-comment-pull-request/compare/fabd468d3a1a0b97feee5f6b9e499eab0dd903f6...e2c37e53a7d2227b61585343765f73a9ca57eda9) --- updated-dependencies: - dependency-name: thollander/actions-comment-pull-request dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/backport.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/backport.yaml b/.github/workflows/backport.yaml index 1f7d064ca3..a7837adfef 100644 --- a/.github/workflows/backport.yaml +++ b/.github/workflows/backport.yaml @@ -60,7 +60,7 @@ jobs: || contains(github.event.label.name, 'semver:major') || contains(github.event.label.name, 'semver:minor') || contains(github.event.label.name, 'semver:unknown') - uses: thollander/actions-comment-pull-request@fabd468d3a1a0b97feee5f6b9e499eab0dd903f6 + uses: thollander/actions-comment-pull-request@e2c37e53a7d2227b61585343765f73a9ca57eda9 with: message: | Labels `semver-major`, `semver-minor` and `semver-unknown` block @@ -119,7 +119,7 @@ jobs: || contains(github.event.pull_request.labels.*.name, 'semver:unknown') || contains(github.event.label.name, 'semver:major') || contains(github.event.label.name, 'semver:unknown') - uses: thollander/actions-comment-pull-request@fabd468d3a1a0b97feee5f6b9e499eab0dd903f6 + uses: thollander/actions-comment-pull-request@e2c37e53a7d2227b61585343765f73a9ca57eda9 with: message: | Labels `semver-major` and `semver-unknown` block backports to the From 470f1bc8d813adf72a36854991ebd843c4e86d42 Mon Sep 17 00:00:00 2001 From: kayrus Date: Fri, 27 Sep 2024 10:00:51 +0200 Subject: [PATCH 046/429] [core]: allow empty struct member updates --- .../acceptance/openstack/compute/v2/aggregates_test.go | 5 +++-- internal/acceptance/openstack/compute/v2/flavors_test.go | 2 +- internal/acceptance/openstack/compute/v2/secgroup_test.go | 2 +- internal/acceptance/openstack/compute/v2/servers_test.go | 2 +- .../openstack/loadbalancer/v2/flavorprofiles_test.go | 5 +++-- .../acceptance/openstack/loadbalancer/v2/flavors_test.go | 5 +++-- internal/ptr/ptr.go | 5 +++++ openstack/compute/v2/aggregates/requests.go | 4 ++-- openstack/compute/v2/aggregates/testing/requests_test.go | 6 +++--- openstack/compute/v2/flavors/requests.go | 2 +- openstack/compute/v2/flavors/testing/requests_test.go | 3 ++- openstack/compute/v2/secgroups/requests.go | 2 +- openstack/compute/v2/secgroups/testing/requests_test.go | 6 +++--- openstack/compute/v2/servers/requests.go | 6 +++--- openstack/compute/v2/servers/testing/requests_test.go | 3 ++- openstack/loadbalancer/v2/flavorprofiles/requests.go | 6 +++--- .../v2/flavorprofiles/testing/requests_test.go | 7 ++++--- openstack/loadbalancer/v2/flavors/requests.go | 6 +++--- openstack/loadbalancer/v2/flavors/testing/requests_test.go | 7 ++++--- 19 files changed, 48 insertions(+), 36 deletions(-) create mode 100644 internal/ptr/ptr.go diff --git a/internal/acceptance/openstack/compute/v2/aggregates_test.go b/internal/acceptance/openstack/compute/v2/aggregates_test.go index 88ac3a3365..4b20b3ff29 100644 --- a/internal/acceptance/openstack/compute/v2/aggregates_test.go +++ b/internal/acceptance/openstack/compute/v2/aggregates_test.go @@ -11,6 +11,7 @@ import ( "github.com/gophercloud/gophercloud/v2" "github.com/gophercloud/gophercloud/v2/internal/acceptance/clients" "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" + "github.com/gophercloud/gophercloud/v2/internal/ptr" "github.com/gophercloud/gophercloud/v2/openstack/compute/v2/aggregates" "github.com/gophercloud/gophercloud/v2/openstack/compute/v2/hypervisors" th "github.com/gophercloud/gophercloud/v2/testhelper" @@ -47,8 +48,8 @@ func TestAggregatesCRUD(t *testing.T) { tools.PrintResource(t, aggregate) updateOpts := aggregates.UpdateOpts{ - Name: "new_aggregate_name", - AvailabilityZone: "new_azone", + Name: ptr.To("new_aggregate_name"), + AvailabilityZone: ptr.To("new_azone"), } updatedAggregate, err := aggregates.Update(context.TODO(), client, aggregate.ID, updateOpts).Extract() diff --git a/internal/acceptance/openstack/compute/v2/flavors_test.go b/internal/acceptance/openstack/compute/v2/flavors_test.go index 412149adfe..7a6ca6b2d5 100644 --- a/internal/acceptance/openstack/compute/v2/flavors_test.go +++ b/internal/acceptance/openstack/compute/v2/flavors_test.go @@ -135,7 +135,7 @@ func TestFlavorsCreateUpdateDelete(t *testing.T) { newFlavorDescription := "This is the new description" updateOpts := flavors.UpdateOpts{ - Description: newFlavorDescription, + Description: &newFlavorDescription, } flavor, err = flavors.Update(context.TODO(), client, flavor.ID, updateOpts).Extract() diff --git a/internal/acceptance/openstack/compute/v2/secgroup_test.go b/internal/acceptance/openstack/compute/v2/secgroup_test.go index dd6b6dd85e..0a883d3789 100644 --- a/internal/acceptance/openstack/compute/v2/secgroup_test.go +++ b/internal/acceptance/openstack/compute/v2/secgroup_test.go @@ -48,7 +48,7 @@ func TestSecGroupsCRUD(t *testing.T) { newName := tools.RandomString("secgroup_", 4) description := "" updateOpts := secgroups.UpdateOpts{ - Name: newName, + Name: &newName, Description: &description, } updatedSecurityGroup, err := secgroups.Update(context.TODO(), client, securityGroup.ID, updateOpts).Extract() diff --git a/internal/acceptance/openstack/compute/v2/servers_test.go b/internal/acceptance/openstack/compute/v2/servers_test.go index 5934805ba2..67ef63028f 100644 --- a/internal/acceptance/openstack/compute/v2/servers_test.go +++ b/internal/acceptance/openstack/compute/v2/servers_test.go @@ -133,7 +133,7 @@ func TestServersUpdate(t *testing.T) { t.Logf("Attempting to rename the server to %s.", alternateName) updateOpts := servers.UpdateOpts{ - Name: alternateName, + Name: &alternateName, } updated, err := servers.Update(context.TODO(), client, server.ID, updateOpts).Extract() diff --git a/internal/acceptance/openstack/loadbalancer/v2/flavorprofiles_test.go b/internal/acceptance/openstack/loadbalancer/v2/flavorprofiles_test.go index 1a6ebadf28..7151a3458b 100644 --- a/internal/acceptance/openstack/loadbalancer/v2/flavorprofiles_test.go +++ b/internal/acceptance/openstack/loadbalancer/v2/flavorprofiles_test.go @@ -8,6 +8,7 @@ import ( "github.com/gophercloud/gophercloud/v2/internal/acceptance/clients" "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" + "github.com/gophercloud/gophercloud/v2/internal/ptr" "github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/flavorprofiles" th "github.com/gophercloud/gophercloud/v2/testhelper" @@ -41,13 +42,13 @@ func TestFlavorProfilesCRUD(t *testing.T) { th.AssertEquals(t, "amphora", flavorProfile.ProviderName) flavorProfileUpdateOpts := flavorprofiles.UpdateOpts{ - Name: tools.RandomString("TESTACCTUP-", 8), + Name: ptr.To(tools.RandomString("TESTACCTUP-", 8)), } flavorProfileUpdated, err := flavorprofiles.Update(context.TODO(), lbClient, flavorProfile.ID, flavorProfileUpdateOpts).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, flavorProfileUpdateOpts.Name, flavorProfileUpdated.Name) + th.AssertEquals(t, *flavorProfileUpdateOpts.Name, flavorProfileUpdated.Name) t.Logf("Successfully updated flavorprofile %s", flavorProfileUpdated.Name) } diff --git a/internal/acceptance/openstack/loadbalancer/v2/flavors_test.go b/internal/acceptance/openstack/loadbalancer/v2/flavors_test.go index b714af7324..40bd1cc11a 100644 --- a/internal/acceptance/openstack/loadbalancer/v2/flavors_test.go +++ b/internal/acceptance/openstack/loadbalancer/v2/flavors_test.go @@ -8,6 +8,7 @@ import ( "github.com/gophercloud/gophercloud/v2/internal/acceptance/clients" "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" + "github.com/gophercloud/gophercloud/v2/internal/ptr" "github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/flavors" th "github.com/gophercloud/gophercloud/v2/testhelper" ) @@ -54,13 +55,13 @@ func TestFlavorsCRUD(t *testing.T) { th.AssertEquals(t, flavor.FlavorProfileId, flavorProfile.ID) flavorUpdateOpts := flavors.UpdateOpts{ - Name: tools.RandomString("TESTACCTUP-", 8), + Name: ptr.To(tools.RandomString("TESTACCTUP-", 8)), } flavorUpdated, err := flavors.Update(context.TODO(), lbClient, flavor.ID, flavorUpdateOpts).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, flavorUpdateOpts.Name, flavorUpdated.Name) + th.AssertEquals(t, *flavorUpdateOpts.Name, flavorUpdated.Name) t.Logf("Successfully updated flavor %s", flavorUpdated.Name) } diff --git a/internal/ptr/ptr.go b/internal/ptr/ptr.go new file mode 100644 index 0000000000..6c3ee9bd51 --- /dev/null +++ b/internal/ptr/ptr.go @@ -0,0 +1,5 @@ +package ptr + +func To[T any](v T) *T { + return &v +} diff --git a/openstack/compute/v2/aggregates/requests.go b/openstack/compute/v2/aggregates/requests.go index 7111c203b0..be20cbffe2 100644 --- a/openstack/compute/v2/aggregates/requests.go +++ b/openstack/compute/v2/aggregates/requests.go @@ -66,13 +66,13 @@ func Get(ctx context.Context, client *gophercloud.ServiceClient, aggregateID int type UpdateOpts struct { // The name of the host aggregate. - Name string `json:"name,omitempty"` + Name *string `json:"name,omitempty"` // The availability zone of the host aggregate. // You should use a custom availability zone rather than // the default returned by the os-availability-zone API. // The availability zone must not include ‘:’ in its name. - AvailabilityZone string `json:"availability_zone,omitempty"` + AvailabilityZone *string `json:"availability_zone,omitempty"` } func (opts UpdateOpts) ToAggregatesUpdateMap() (map[string]any, error) { diff --git a/openstack/compute/v2/aggregates/testing/requests_test.go b/openstack/compute/v2/aggregates/testing/requests_test.go index 2e229bf71c..601150a58d 100644 --- a/openstack/compute/v2/aggregates/testing/requests_test.go +++ b/openstack/compute/v2/aggregates/testing/requests_test.go @@ -4,6 +4,7 @@ import ( "context" "testing" + "github.com/gophercloud/gophercloud/v2/internal/ptr" "github.com/gophercloud/gophercloud/v2/openstack/compute/v2/aggregates" "github.com/gophercloud/gophercloud/v2/pagination" th "github.com/gophercloud/gophercloud/v2/testhelper" @@ -86,10 +87,9 @@ func TestUpdateAggregate(t *testing.T) { HandleUpdateSuccessfully(t) expected := UpdatedAggregate - opts := aggregates.UpdateOpts{ - Name: "test-aggregates2", - AvailabilityZone: "nova2", + Name: ptr.To("test-aggregates2"), + AvailabilityZone: ptr.To("nova2"), } actual, err := aggregates.Update(context.TODO(), client.ServiceClient(), expected.ID, opts).Extract() diff --git a/openstack/compute/v2/flavors/requests.go b/openstack/compute/v2/flavors/requests.go index 119f5e78e8..fe27fe97da 100644 --- a/openstack/compute/v2/flavors/requests.go +++ b/openstack/compute/v2/flavors/requests.go @@ -165,7 +165,7 @@ type UpdateOpts struct { // Description is a free form description of the flavor. Limited to // 65535 characters in length. Only printable characters are allowed. // New in version 2.55 - Description string `json:"description,omitempty"` + Description *string `json:"description,omitempty"` } // ToFlavorUpdateMap constructs a request body from UpdateOpts. diff --git a/openstack/compute/v2/flavors/testing/requests_test.go b/openstack/compute/v2/flavors/testing/requests_test.go index d22e3dfa9c..79710fc126 100644 --- a/openstack/compute/v2/flavors/testing/requests_test.go +++ b/openstack/compute/v2/flavors/testing/requests_test.go @@ -7,6 +7,7 @@ import ( "reflect" "testing" + "github.com/gophercloud/gophercloud/v2/internal/ptr" "github.com/gophercloud/gophercloud/v2/openstack/compute/v2/flavors" "github.com/gophercloud/gophercloud/v2/pagination" th "github.com/gophercloud/gophercloud/v2/testhelper" @@ -242,7 +243,7 @@ func TestUpdateFlavor(t *testing.T) { }) opts := &flavors.UpdateOpts{ - Description: "foo", + Description: ptr.To("foo"), } actual, err := flavors.Update(context.TODO(), fake.ServiceClient(), "12345678", opts).Extract() if err != nil { diff --git a/openstack/compute/v2/secgroups/requests.go b/openstack/compute/v2/secgroups/requests.go index d69a99b4f0..c43575aeb4 100644 --- a/openstack/compute/v2/secgroups/requests.go +++ b/openstack/compute/v2/secgroups/requests.go @@ -61,7 +61,7 @@ func Create(ctx context.Context, client *gophercloud.ServiceClient, opts CreateO // UpdateOpts is the struct responsible for updating an existing security group. type UpdateOpts struct { // the name of your security group. - Name string `json:"name,omitempty"` + Name *string `json:"name,omitempty"` // the description of your security group. Description *string `json:"description,omitempty"` } diff --git a/openstack/compute/v2/secgroups/testing/requests_test.go b/openstack/compute/v2/secgroups/testing/requests_test.go index 222295d5e8..53c473ce0a 100644 --- a/openstack/compute/v2/secgroups/testing/requests_test.go +++ b/openstack/compute/v2/secgroups/testing/requests_test.go @@ -4,6 +4,7 @@ import ( "context" "testing" + "github.com/gophercloud/gophercloud/v2/internal/ptr" "github.com/gophercloud/gophercloud/v2/openstack/compute/v2/secgroups" "github.com/gophercloud/gophercloud/v2/pagination" th "github.com/gophercloud/gophercloud/v2/testhelper" @@ -116,10 +117,9 @@ func TestUpdate(t *testing.T) { mockUpdateGroupResponse(t, groupID) - description := "new_desc" opts := secgroups.UpdateOpts{ - Name: "new_name", - Description: &description, + Name: ptr.To("new_name"), + Description: ptr.To("new_desc"), } group, err := secgroups.Update(context.TODO(), client.ServiceClient(), groupID, opts).Extract() diff --git a/openstack/compute/v2/servers/requests.go b/openstack/compute/v2/servers/requests.go index dd3b132d1d..d7d5ad81c1 100644 --- a/openstack/compute/v2/servers/requests.go +++ b/openstack/compute/v2/servers/requests.go @@ -641,13 +641,13 @@ type UpdateOpts struct { // Name changes the displayed name of the server. // The server host name will *not* change. // Server names are not constrained to be unique, even within the same tenant. - Name string `json:"name,omitempty"` + Name *string `json:"name,omitempty"` // AccessIPv4 provides a new IPv4 address for the instance. - AccessIPv4 string `json:"accessIPv4,omitempty"` + AccessIPv4 *string `json:"accessIPv4,omitempty"` // AccessIPv6 provides a new IPv6 address for the instance. - AccessIPv6 string `json:"accessIPv6,omitempty"` + AccessIPv6 *string `json:"accessIPv6,omitempty"` } // ToServerUpdateMap formats an UpdateOpts structure into a request body. diff --git a/openstack/compute/v2/servers/testing/requests_test.go b/openstack/compute/v2/servers/testing/requests_test.go index b6ebefce5e..8024add04e 100644 --- a/openstack/compute/v2/servers/testing/requests_test.go +++ b/openstack/compute/v2/servers/testing/requests_test.go @@ -7,6 +7,7 @@ import ( "net/http" "testing" + "github.com/gophercloud/gophercloud/v2/internal/ptr" "github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers" "github.com/gophercloud/gophercloud/v2/pagination" th "github.com/gophercloud/gophercloud/v2/testhelper" @@ -807,7 +808,7 @@ func TestUpdateServer(t *testing.T) { HandleServerUpdateSuccessfully(t) client := client.ServiceClient() - actual, err := servers.Update(context.TODO(), client, "1234asdf", servers.UpdateOpts{Name: "new-name"}).Extract() + actual, err := servers.Update(context.TODO(), client, "1234asdf", servers.UpdateOpts{Name: ptr.To("new-name")}).Extract() if err != nil { t.Fatalf("Unexpected Update error: %v", err) } diff --git a/openstack/loadbalancer/v2/flavorprofiles/requests.go b/openstack/loadbalancer/v2/flavorprofiles/requests.go index e51b9d99e6..3c764592cc 100644 --- a/openstack/loadbalancer/v2/flavorprofiles/requests.go +++ b/openstack/loadbalancer/v2/flavorprofiles/requests.go @@ -100,13 +100,13 @@ type UpdateOptsBuilder interface { // operation. type UpdateOpts struct { // Human-readable name for the Loadbalancer. Does not have to be unique. - Name string `json:"name,omitempty"` + Name *string `json:"name,omitempty"` // Providing the name of the provider supported by the Octavia installation. - ProviderName string `json:"provider_name,omitempty"` + ProviderName *string `json:"provider_name,omitempty"` // Providing the json string containing the flavor metadata. - FlavorData string `json:"flavor_data,omitempty"` + FlavorData *string `json:"flavor_data,omitempty"` } // ToFlavorProfileUpdateMap builds a request body from UpdateOpts. diff --git a/openstack/loadbalancer/v2/flavorprofiles/testing/requests_test.go b/openstack/loadbalancer/v2/flavorprofiles/testing/requests_test.go index aebb2c9408..5cefc8c971 100644 --- a/openstack/loadbalancer/v2/flavorprofiles/testing/requests_test.go +++ b/openstack/loadbalancer/v2/flavorprofiles/testing/requests_test.go @@ -4,6 +4,7 @@ import ( "context" "testing" + "github.com/gophercloud/gophercloud/v2/internal/ptr" "github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/flavorprofiles" "github.com/gophercloud/gophercloud/v2/pagination" @@ -106,9 +107,9 @@ func TestUpdateFlavorProfile(t *testing.T) { client := fake.ServiceClient() actual, err := flavorprofiles.Update(context.TODO(), client, "dcd65be5-f117-4260-ab3d-b32cc5bd1272", flavorprofiles.UpdateOpts{ - Name: "amphora-test-updated", - ProviderName: "amphora", - FlavorData: "{\"loadbalancer_topology\": \"SINGLE\"}", + Name: ptr.To("amphora-test-updated"), + ProviderName: ptr.To("amphora"), + FlavorData: ptr.To(`{"loadbalancer_topology": "SINGLE"}`), }).Extract() if err != nil { t.Fatalf("Unexpected Update error: %v", err) diff --git a/openstack/loadbalancer/v2/flavors/requests.go b/openstack/loadbalancer/v2/flavors/requests.go index 710a6edf5b..4a0640d5ae 100644 --- a/openstack/loadbalancer/v2/flavors/requests.go +++ b/openstack/loadbalancer/v2/flavors/requests.go @@ -106,13 +106,13 @@ type UpdateOptsBuilder interface { // operation. type UpdateOpts struct { // Human-readable name for the Loadbalancer. Does not have to be unique. - Name string `json:"name,omitempty"` + Name *string `json:"name,omitempty"` // Human-readable description for the Flavor. - Description string `json:"description,omitempty"` + Description *string `json:"description,omitempty"` // If the resource is available for use. - Enabled bool `json:"enabled,omitempty"` + Enabled *bool `json:"enabled,omitempty"` } // ToFlavorUpdateMap builds a request body from UpdateOpts. diff --git a/openstack/loadbalancer/v2/flavors/testing/requests_test.go b/openstack/loadbalancer/v2/flavors/testing/requests_test.go index fd668a2134..80a9ad2d05 100644 --- a/openstack/loadbalancer/v2/flavors/testing/requests_test.go +++ b/openstack/loadbalancer/v2/flavors/testing/requests_test.go @@ -6,6 +6,7 @@ import ( "net/http" "testing" + "github.com/gophercloud/gophercloud/v2/internal/ptr" "github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/flavors" "github.com/gophercloud/gophercloud/v2/pagination" @@ -154,9 +155,9 @@ func TestUpdateFlavor(t *testing.T) { client := fake.ServiceClient() actual, err := flavors.Update(context.TODO(), client, "5548c807-e6e8-43d7-9ea4-b38d34dd74a0", flavors.UpdateOpts{ - Name: "Basic v2", - Description: "Rename flavor", - Enabled: true, + Name: ptr.To("Basic v2"), + Description: ptr.To("Rename flavor"), + Enabled: ptr.To(true), }).Extract() if err != nil { t.Fatalf("Unexpected Update error: %v", err) From c9703e7913d8c333b79a593a8b22bfdca3b5f06d Mon Sep 17 00:00:00 2001 From: kayrus Date: Fri, 27 Sep 2024 10:24:14 +0200 Subject: [PATCH 047/429] [octavia]: allow creating a disabled flavor Octavia Flavor's `enabled` is true by default --- .../openstack/loadbalancer/v2/loadbalancer.go | 5 ++- openstack/loadbalancer/v2/flavors/requests.go | 2 +- .../v2/flavors/testing/fixtures.go | 39 +++++++++++++++++++ .../v2/flavors/testing/requests_test.go | 18 ++++++++- 4 files changed, 60 insertions(+), 4 deletions(-) diff --git a/internal/acceptance/openstack/loadbalancer/v2/loadbalancer.go b/internal/acceptance/openstack/loadbalancer/v2/loadbalancer.go index e8596506ef..907e9d5658 100644 --- a/internal/acceptance/openstack/loadbalancer/v2/loadbalancer.go +++ b/internal/acceptance/openstack/loadbalancer/v2/loadbalancer.go @@ -10,6 +10,7 @@ import ( "github.com/gophercloud/gophercloud/v2" "github.com/gophercloud/gophercloud/v2/internal/acceptance/clients" "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" + "github.com/gophercloud/gophercloud/v2/internal/ptr" "github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/flavorprofiles" "github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/flavors" "github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/l7policies" @@ -724,7 +725,7 @@ func CreateFlavor(t *testing.T, client *gophercloud.ServiceClient, flavorProfile Name: flavorName, Description: description, FlavorProfileId: flavorProfile.ID, - Enabled: true, + Enabled: ptr.To(false), } flavor, err := flavors.Create(context.TODO(), client, createOpts).Extract() @@ -737,7 +738,7 @@ func CreateFlavor(t *testing.T, client *gophercloud.ServiceClient, flavorProfile th.AssertEquals(t, flavorName, flavor.Name) th.AssertEquals(t, description, flavor.Description) th.AssertEquals(t, flavorProfile.ID, flavor.FlavorProfileId) - th.AssertEquals(t, true, flavor.Enabled) + th.AssertEquals(t, false, flavor.Enabled) return flavor, nil } diff --git a/openstack/loadbalancer/v2/flavors/requests.go b/openstack/loadbalancer/v2/flavors/requests.go index 4a0640d5ae..499bb3bd0d 100644 --- a/openstack/loadbalancer/v2/flavors/requests.go +++ b/openstack/loadbalancer/v2/flavors/requests.go @@ -68,7 +68,7 @@ type CreateOpts struct { FlavorProfileId string `json:"flavor_profile_id" required:"true"` // If the resource is available for use. The default is True. - Enabled bool `json:"enabled,omitempty"` + Enabled *bool `json:"enabled,omitempty"` } // ToFlavorCreateMap builds a request body from CreateOpts. diff --git a/openstack/loadbalancer/v2/flavors/testing/fixtures.go b/openstack/loadbalancer/v2/flavors/testing/fixtures.go index a3169d7ece..5423ca16b7 100644 --- a/openstack/loadbalancer/v2/flavors/testing/fixtures.go +++ b/openstack/loadbalancer/v2/flavors/testing/fixtures.go @@ -44,6 +44,18 @@ const SingleFlavorBody = ` } ` +const SingleFlavorDisabledBody = ` +{ + "flavor": { + "id": "5548c807-e6e8-43d7-9ea4-b38d34dd74a0", + "name": "Basic", + "description": "A basic standalone Octavia load balancer.", + "enabled": false, + "flavor_profile_id": "9daa2768-74e7-4d13-bf5d-1b8e0dc239e1" + } +} +` + const PostUpdateFlavorBody = ` { "flavor": { @@ -81,6 +93,14 @@ var ( FlavorProfileId: "9daa2768-74e7-4d13-bf5d-1b8e0dc239e1", } + FlavorDisabled = flavors.Flavor{ + ID: "5548c807-e6e8-43d7-9ea4-b38d34dd74a0", + Name: "Basic", + Description: "A basic standalone Octavia load balancer.", + Enabled: false, + FlavorProfileId: "9daa2768-74e7-4d13-bf5d-1b8e0dc239e1", + } + FlavorUpdated = flavors.Flavor{ ID: "5548c807-e6e8-43d7-9ea4-b38d34dd74a0", Name: "Basic v2", @@ -130,6 +150,25 @@ func HandleFlavorCreationSuccessfully(t *testing.T, response string) { }) } +func HandleFlavorCreationSuccessfullyDisabled(t *testing.T, response string) { + th.Mux.HandleFunc("/v2.0/lbaas/flavors", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.TestJSONRequest(t, r, `{ + "flavor": { + "name": "Basic", + "description": "A basic standalone Octavia load balancer.", + "enabled": false, + "flavor_profile_id": "9daa2768-74e7-4d13-bf5d-1b8e0dc239e1" + } + }`) + + w.WriteHeader(http.StatusAccepted) + w.Header().Add("Content-Type", "application/json") + fmt.Fprintf(w, response) + }) +} + func HandleFlavorGetSuccessfully(t *testing.T) { th.Mux.HandleFunc("/v2.0/lbaas/flavors/5548c807-e6e8-43d7-9ea4-b38d34dd74a0", func(w http.ResponseWriter, r *http.Request) { th.TestMethod(t, r, "GET") diff --git a/openstack/loadbalancer/v2/flavors/testing/requests_test.go b/openstack/loadbalancer/v2/flavors/testing/requests_test.go index 80a9ad2d05..5b19f962ca 100644 --- a/openstack/loadbalancer/v2/flavors/testing/requests_test.go +++ b/openstack/loadbalancer/v2/flavors/testing/requests_test.go @@ -110,7 +110,7 @@ func TestCreateFlavor(t *testing.T) { actual, err := flavors.Create(context.TODO(), fake.ServiceClient(), flavors.CreateOpts{ Name: "Basic", Description: "A basic standalone Octavia load balancer.", - Enabled: true, + Enabled: ptr.To(true), FlavorProfileId: "9daa2768-74e7-4d13-bf5d-1b8e0dc239e1", }).Extract() th.AssertNoErr(t, err) @@ -118,6 +118,22 @@ func TestCreateFlavor(t *testing.T) { th.CheckDeepEquals(t, FlavorDb, *actual) } +func TestCreateFlavorDisabled(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + HandleFlavorCreationSuccessfullyDisabled(t, SingleFlavorDisabledBody) + + actual, err := flavors.Create(context.TODO(), fake.ServiceClient(), flavors.CreateOpts{ + Name: "Basic", + Description: "A basic standalone Octavia load balancer.", + Enabled: ptr.To(false), + FlavorProfileId: "9daa2768-74e7-4d13-bf5d-1b8e0dc239e1", + }).Extract() + th.AssertNoErr(t, err) + + th.CheckDeepEquals(t, FlavorDisabled, *actual) +} + func TestRequiredCreateOpts(t *testing.T) { res := flavors.Create(context.TODO(), fake.ServiceClient(), flavors.CreateOpts{}) if res.Err == nil { From 3966ef34a7fe9c5518d23a4452b23a12a4d55893 Mon Sep 17 00:00:00 2001 From: Pierre Prinetti Date: Thu, 17 Oct 2024 10:23:58 +0200 Subject: [PATCH 048/429] docs: Remove outdated godoc The `doc.go` file, and [go.dev](https://pkg.go.dev/github.com/gophercloud/gophercloud/v2) as a consequence, was still recommending to use utils for authentication. Since the automatically-generated documentation on the Go website already includes the README, we can delete doc.go and keep README.md as the canonical introduction to the module. --- README.md | 2 - doc.go | 148 ------------------------------------------------------ 2 files changed, 150 deletions(-) delete mode 100644 doc.go diff --git a/README.md b/README.md index e9ba39bb79..ca47f5b0ba 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ # Gophercloud: an OpenStack SDK for Go [![Coverage Status](https://coveralls.io/repos/github/gophercloud/gophercloud/badge.svg?branch=master)](https://coveralls.io/github/gophercloud/gophercloud?branch=master) -[Reference documentation](http://godoc.org/github.com/gophercloud/gophercloud/v2) - Gophercloud is a Go SDK for OpenStack. Join us on kubernetes slack, on [#gophercloud](https://kubernetes.slack.com/archives/C05G4NJ6P6X). Visit [slack.k8s.io](https://slack.k8s.io) for an invitation. diff --git a/doc.go b/doc.go deleted file mode 100644 index a755ecb180..0000000000 --- a/doc.go +++ /dev/null @@ -1,148 +0,0 @@ -/* -Package gophercloud provides a multi-vendor interface to OpenStack-compatible -clouds. The library has a three-level hierarchy: providers, services, and -resources. - -# Authenticating with Providers - -Provider structs represent the cloud providers that offer and manage a -collection of services. You will generally want to create one Provider -client per OpenStack cloud. - - It is now recommended to use the `clientconfig` package found at - https://github.com/gophercloud/utils/tree/master/openstack/clientconfig - for all authentication purposes. - - The below documentation is still relevant. clientconfig simply implements - the below and presents it in an easier and more flexible way. - -Use your OpenStack credentials to create a Provider client. The -IdentityEndpoint is typically refered to as "auth_url" or "OS_AUTH_URL" in -information provided by the cloud operator. Additionally, the cloud may refer to -TenantID or TenantName as project_id and project_name. Credentials are -specified like so: - - opts := gophercloud.AuthOptions{ - IdentityEndpoint: "https://openstack.example.com:5000/v2.0", - Username: "{username}", - Password: "{password}", - TenantID: "{tenant_id}", - } - - provider, err := openstack.AuthenticatedClient(context.TODO(), opts) - -You can authenticate with a token by doing: - - opts := gophercloud.AuthOptions{ - IdentityEndpoint: "https://openstack.example.com:5000/v2.0", - TokenID: "{token_id}", - TenantID: "{tenant_id}", - } - - provider, err := openstack.AuthenticatedClient(context.TODO(), opts) - -You may also use the openstack.AuthOptionsFromEnv() helper function. This -function reads in standard environment variables frequently found in an -OpenStack `openrc` file. Again note that Gophercloud currently uses "tenant" -instead of "project". - - opts, err := openstack.AuthOptionsFromEnv() - provider, err := openstack.AuthenticatedClient(context.TODO(), opts) - -# Service Clients - -Service structs are specific to a provider and handle all of the logic and -operations for a particular OpenStack service. Examples of services include: -Compute, Object Storage, Block Storage. In order to define one, you need to -pass in the parent provider, like so: - - opts := gophercloud.EndpointOpts{Region: "RegionOne"} - - client, err := openstack.NewComputeV2(provider, opts) - -# Resources - -Resource structs are the domain models that services make use of in order -to work with and represent the state of API resources: - - server, err := servers.Get(context.TODO(), client, "{serverId}").Extract() - -Intermediate Result structs are returned for API operations, which allow -generic access to the HTTP headers, response body, and any errors associated -with the network transaction. To turn a result into a usable resource struct, -you must call the Extract method which is chained to the response, or an -Extract function from an applicable extension: - - result := servers.Get(context.TODO(), client, "{serverId}") - - // Attempt to extract the disk configuration from the OS-DCF disk config - // extension: - config, err := diskconfig.ExtractGet(result) - -All requests that enumerate a collection return a Pager struct that is used to -iterate through the results one page at a time. Use the EachPage method on that -Pager to handle each successive Page in a closure, then use the appropriate -extraction method from that request's package to interpret that Page as a slice -of results: - - err := servers.List(client, nil).EachPage(context.TODO(), func (_ context.Context, page pagination.Page) (bool, error) { - s, err := servers.ExtractServers(page) - if err != nil { - return false, err - } - - // Handle the []servers.Server slice. - - // Return "false" or an error to prematurely stop fetching new pages. - return true, nil - }) - -If you want to obtain the entire collection of pages without doing any -intermediary processing on each page, you can use the AllPages method: - - allPages, err := servers.List(client, nil).AllPages(context.TODO()) - allServers, err := servers.ExtractServers(allPages) - -This top-level package contains utility functions and data types that are used -throughout the provider and service packages. Of particular note for end users -are the AuthOptions and EndpointOpts structs. - -An example retry backoff function, which respects the 429 HTTP response code and a "Retry-After" header: - - endpoint := "http://localhost:5000" - provider, err := openstack.NewClient(endpoint) - if err != nil { - panic(err) - } - provider.MaxBackoffRetries = 3 // max three retries - provider.RetryBackoffFunc = func(ctx context.Context, respErr *ErrUnexpectedResponseCode, e error, retries uint) error { - retryAfter := respErr.ResponseHeader.Get("Retry-After") - if retryAfter == "" { - return e - } - - var sleep time.Duration - - // Parse delay seconds or HTTP date - if v, err := strconv.ParseUint(retryAfter, 10, 32); err == nil { - sleep = time.Duration(v) * time.Second - } else if v, err := time.Parse(http.TimeFormat, retryAfter); err == nil { - sleep = time.Until(v) - } else { - return e - } - - if ctx != nil { - select { - case <-time.After(sleep): - case <-ctx.Done(): - return e - } - } else { - time.Sleep(sleep) - } - - return nil - } -*/ -package gophercloud From eb799fe35bb0cff797d62d1bdd85c08c82fb8def Mon Sep 17 00:00:00 2001 From: Pierre Prinetti Date: Mon, 21 Oct 2024 12:04:40 +0200 Subject: [PATCH 049/429] Fix clear-needinfo The gh tool must be set to operate on an issue rather than on a PR. --- .github/workflows/label-issue.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/label-issue.yaml b/.github/workflows/label-issue.yaml index 723f4cd04e..a1fbff16e0 100644 --- a/.github/workflows/label-issue.yaml +++ b/.github/workflows/label-issue.yaml @@ -9,9 +9,11 @@ jobs: name: Clear needinfo if: ${{ github.event.issue.user.login }} == ${{ github.event.comment.user.login }} runs-on: ubuntu-latest + permissions: + issues: write steps: - - run: gh pr edit "$NUMBER" --remove-label "needinfo" + - run: gh issue edit "$NUMBER" --remove-label "needinfo" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} - NUMBER: ${{ github.event.pull_request.number }} + NUMBER: ${{ github.event.issue.number }} From c74ec6b293da38c0915737fcf23d2523ec76c98a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 09:11:02 +0000 Subject: [PATCH 050/429] build(deps): bump kiegroup/git-backporting from 4.8.3 to 4.8.4 Bumps [kiegroup/git-backporting](https://github.com/kiegroup/git-backporting) from 4.8.3 to 4.8.4. - [Release notes](https://github.com/kiegroup/git-backporting/releases) - [Changelog](https://github.com/kiegroup/git-backporting/blob/main/CHANGELOG.md) - [Commits](https://github.com/kiegroup/git-backporting/compare/a14014e89e9bac5210298eb1c4047f037b359c97...b9ed3ac959d1479e81bf4f0a5e5f0a72251ce895) --- updated-dependencies: - dependency-name: kiegroup/git-backporting dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/backport.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/backport.yaml b/.github/workflows/backport.yaml index a7837adfef..f8cbaf657c 100644 --- a/.github/workflows/backport.yaml +++ b/.github/workflows/backport.yaml @@ -34,7 +34,7 @@ jobs: if: > contains(github.event.pull_request.labels.*.name, 'semver:patch') || contains(github.event.label.name, 'semver:patch') - uses: kiegroup/git-backporting@a14014e89e9bac5210298eb1c4047f037b359c97 + uses: kiegroup/git-backporting@b9ed3ac959d1479e81bf4f0a5e5f0a72251ce895 with: target-branch: v1 pull-request: ${{ github.event.pull_request.url }} @@ -95,7 +95,7 @@ jobs: || contains(github.event.pull_request.labels.*.name, 'semver:minor') || contains(github.event.label.name, 'semver:patch') || contains(github.event.label.name, 'semver:minor') - uses: kiegroup/git-backporting@a14014e89e9bac5210298eb1c4047f037b359c97 + uses: kiegroup/git-backporting@b9ed3ac959d1479e81bf4f0a5e5f0a72251ce895 with: target-branch: v2 pull-request: ${{ github.event.pull_request.url }} From 4659d9bb9f069d92ed52e7a9193b1a1244c0da6b Mon Sep 17 00:00:00 2001 From: Pierre Prinetti Date: Mon, 4 Nov 2024 11:26:20 +0100 Subject: [PATCH 051/429] actions: Replace external dependency with gh Comment with [gh](https://cli.github.com/). --- .github/workflows/backport.yaml | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/.github/workflows/backport.yaml b/.github/workflows/backport.yaml index f8cbaf657c..69896c8af2 100644 --- a/.github/workflows/backport.yaml +++ b/.github/workflows/backport.yaml @@ -60,11 +60,13 @@ jobs: || contains(github.event.label.name, 'semver:major') || contains(github.event.label.name, 'semver:minor') || contains(github.event.label.name, 'semver:unknown') - uses: thollander/actions-comment-pull-request@e2c37e53a7d2227b61585343765f73a9ca57eda9 - with: - message: | - Labels `semver-major`, `semver-minor` and `semver-unknown` block - backports to the legacy branch `v1`. + run: gh pr comment "$NUMBER" --body "$BODY" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} + NUMBER: ${{ github.event.pull_request.number }} + BODY: > + Labels `semver-major`, `semver-minor` and `semver-unknown` block backports to the legacy branch `v1`. backport_v2: name: "Backport to v2" @@ -119,8 +121,10 @@ jobs: || contains(github.event.pull_request.labels.*.name, 'semver:unknown') || contains(github.event.label.name, 'semver:major') || contains(github.event.label.name, 'semver:unknown') - uses: thollander/actions-comment-pull-request@e2c37e53a7d2227b61585343765f73a9ca57eda9 - with: - message: | - Labels `semver-major` and `semver-unknown` block backports to the - stable branch `v2`. + run: gh pr comment "$NUMBER" --body "$BODY" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} + NUMBER: ${{ github.event.pull_request.number }} + BODY: > + Labels `semver-major` and `semver-unknown` block backports to the stable branch `v2`. From 700c3fd3a0a4f855b6e9f1e81f36688948d54292 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Nov 2024 09:21:06 +0000 Subject: [PATCH 052/429] build(deps): bump golang.org/x/crypto from 0.28.0 to 0.29.0 Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.28.0 to 0.29.0. - [Commits](https://github.com/golang/crypto/compare/v0.28.0...v0.29.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 8e527ec8e5..45961985de 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module github.com/gophercloud/gophercloud/v2 go 1.22 require ( - golang.org/x/crypto v0.28.0 + golang.org/x/crypto v0.29.0 gopkg.in/yaml.v2 v2.4.0 ) -require golang.org/x/sys v0.26.0 // indirect +require golang.org/x/sys v0.27.0 // indirect diff --git a/go.sum b/go.sum index 7cc4cf43b5..a14f597436 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ -golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= -golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= -golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= -golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= -golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= +golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= +golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= +golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= From 0e5b612d57257cf88fb061c2245c4b52eb290cd8 Mon Sep 17 00:00:00 2001 From: Anthony ROUSSEL Date: Sat, 16 Nov 2024 21:19:52 +0100 Subject: [PATCH 053/429] Adding CI job for testing workflow (Mistral) --- .github/workflows/functional-workflow.yaml | 67 ++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 .github/workflows/functional-workflow.yaml diff --git a/.github/workflows/functional-workflow.yaml b/.github/workflows/functional-workflow.yaml new file mode 100644 index 0000000000..f124fc6412 --- /dev/null +++ b/.github/workflows/functional-workflow.yaml @@ -0,0 +1,67 @@ +name: functional-workflow +on: + pull_request: + paths: + - '**workflow**' + schedule: + - cron: '0 0 */3 * *' +jobs: + functional-workflow: + strategy: + fail-fast: false + matrix: + include: + - name: "master" + openstack_version: "master" + ubuntu_version: "22.04" + mistral_plugin_version: "master" + additional_services: "openstack-cli-server" + - name: "dalmatian" + openstack_version: "stable/2024.2" + ubuntu_version: "22.04" + mistral_plugin_version: "stable/2024.2" + additional_services: "openstack-cli-server" + - name: "caracal" + openstack_version: "stable/2024.1" + ubuntu_version: "22.04" + mistral_plugin_version: "stable/2024.1" + additional_services: "" + - name: "bobcat" + openstack_version: "stable/2023.2" + ubuntu_version: "22.04" + # Devstack support is broken with Mistral v2023.2, and requires 2 patches: + # * https://github.com/openstack/mistral/commit/e343ccb078d8ba261ac70afca93f4358589730d3 + # * https://github.com/openstack/mistral/commit/ecdeadeb7a1aa87cba2cdb0c1a2bb1ffc4aabf25 + mistral_plugin_version: "ecdeadeb7a1aa87cba2cdb0c1a2bb1ffc4aabf25" + additional_services: "" + runs-on: ubuntu-${{ matrix.ubuntu_version }} + name: Deploy OpenStack ${{ matrix.name }} with Mistral and run workflow acceptance tests + steps: + - name: Checkout Gophercloud + uses: actions/checkout@v4 + - name: Deploy devstack + uses: EmilienM/devstack-action@e82a9cbead099cba72f99537e82a360c3e319c69 + with: + branch: ${{ matrix.openstack_version }} + conf_overrides: | + enable_plugin mistral https://github.com/openstack/mistral ${{ matrix.mistral_plugin_version }} + enabled_services: "mistral,mistral-api,mistral-engine,mistral-executor,mistral-event-engine,${{ matrix.additional_services }}" + - name: Checkout go + uses: actions/setup-go@v5 + with: + go-version: '^1.22' + - name: Run Gophercloud acceptance tests + run: ./script/acceptancetest + env: + DEVSTACK_PATH: ${{ github.workspace }}/devstack + PACKAGE: "./internal/acceptance/openstack/workflow/..." + OS_BRANCH: ${{ matrix.openstack_version }} + - name: Generate logs on failure + run: ./script/collectlogs + if: failure() + - name: Upload logs artifacts on failure + if: failure() + uses: actions/upload-artifact@v4 + with: + name: functional-workflow-${{ matrix.name }}-${{ github.run_id }} + path: /tmp/devstack-logs/* From 3d2bb51a2a1dd1feedf7f190b8688dfaf15ddbac Mon Sep 17 00:00:00 2001 From: Sharpz7 Date: Wed, 30 Oct 2024 01:06:21 +0000 Subject: [PATCH 054/429] Added fields for Node API Parity --- openstack/baremetal/v1/nodes/results.go | 82 ++++++++--- .../v1/nodes/testing/fixtures_test.go | 133 +++++++++++++++--- 2 files changed, 177 insertions(+), 38 deletions(-) diff --git a/openstack/baremetal/v1/nodes/results.go b/openstack/baremetal/v1/nodes/results.go index 5c6eb5c190..22babe02d3 100644 --- a/openstack/baremetal/v1/nodes/results.go +++ b/openstack/baremetal/v1/nodes/results.go @@ -90,12 +90,19 @@ func (r SubscriptionVendorPassthruResult) Extract() (*SubscriptionVendorPassthru return &s, err } +// Link represents a hyperlink and its relationship to the current resource. +type Link struct { + // Href is the URL of the related resource. + Href string `json:"href"` + + // Rel describes the relationship of the resource to the current + // context (e.g., "self", "bookmark"). + Rel string `json:"rel"` +} + // Node represents a node in the OpenStack Bare Metal API. +// https://docs.openstack.org/api-ref/baremetal/#list-nodes-detailed type Node struct { - // Whether automated cleaning is enabled or disabled on this node. - // Requires microversion 1.47 or later. - AutomatedClean *bool `json:"automated_clean"` - // UUID for the resource. UUID string `json:"uuid"` @@ -183,8 +190,17 @@ type Node struct { // Current deploy step. DeployStep map[string]any `json:"deploy_step"` - // Current service step. - ServiceStep map[string]any `json:"service_step"` + // A list of relative links. Includes the self and bookmark links. + Links []Link `json:"links"` + + // Links to the collection of ports on this node + Ports []Link `json:"ports"` + + // Links to the collection of portgroups on this node. + PortGroups []Link `json:"portgroups"` + + // Links to the collection of states. Note that this resource is also used to request state transitions. + States []Link `json:"states"` // String which can be used by external schedulers to identify this Node as a unit of a specific type of resource. // For more details, see: https://docs.openstack.org/ironic/latest/install/configure-nova-flavors.html @@ -202,9 +218,6 @@ type Node struct { // Deploy interface for a node, e.g. “iscsi”. DeployInterface string `json:"deploy_interface"` - // Firmware interface for a node, e.g. “redfish”. - FirmwareInterface string `json:"firmware_interface"` - // Interface used for node inspection, e.g. “no-inspect”. InspectInterface string `json:"inspect_interface"` @@ -232,9 +245,15 @@ type Node struct { // For vendor-specific functionality on this node, e.g. “no-vendor”. VendorInterface string `json:"vendor_interface"` + // Links to the volume resources. + Volume []Link `json:"volume"` + // Conductor group for a node. Case-insensitive string up to 255 characters, containing a-z, 0-9, _, -, and .. ConductorGroup string `json:"conductor_group"` + // An optional UUID which can be used to denote the “parent” baremetal node. + ParentNode string `json:"parent_node"` + // The node is protected from undeploying, rebuilding and deletion. Protected bool `json:"protected"` @@ -244,14 +263,42 @@ type Node struct { // A string or UUID of the tenant who owns the baremetal node. Owner string `json:"owner"` + // A string or UUID of the tenant who is leasing the object. + Lessee string `json:"lessee"` + + // A string indicating the shard this node belongs to. + Shard string `json:"shard"` + + // Informational text about this node. + Description string `json:"description"` + + // The conductor currently servicing a node. This field is read-only. + Conductor string `json:"conductor"` + + // The UUID of the allocation associated with the node. If not null, will be the same as instance_uuid + // (the opposite is not always true). Unlike instance_uuid, this field is read-only. Please use the + // Allocation API to remove allocations. + AllocationUUID string `json:"allocation_uuid"` + + // Whether the node is retired. A Node tagged as retired will prevent any further + // scheduling of instances, but will still allow for other operations, such as cleaning, to happen + Retired bool `json:"retired"` + + // Reason the node is marked as retired. + RetiredReason string `json:"retired_reason"` + // Static network configuration to use during deployment and cleaning. NetworkData map[string]any `json:"network_data"` - // The UTC date and time when the resource was created, ISO 8601 format. - CreatedAt time.Time `json:"created_at"` + // Whether automated cleaning is enabled or disabled on this node. + // Requires microversion 1.47 or later. + AutomatedClean *bool `json:"automated_clean"` - // The UTC date and time when the resource was updated, ISO 8601 format. May be “null”. - UpdatedAt time.Time `json:"updated_at"` + // Current service step. + ServiceStep map[string]any `json:"service_step"` + + // Firmware interface for a node, e.g. “redfish”. + FirmwareInterface string `json:"firmware_interface"` // The UTC date and time when the provision state was updated, ISO 8601 format. May be “null”. ProvisionUpdatedAt time.Time `json:"provision_updated_at"` @@ -262,12 +309,11 @@ type Node struct { // The UTC date and time when the last inspection was finished, ISO 8601 format. May be “null” if inspection hasn't been finished yet. InspectionFinishedAt *time.Time `json:"inspection_finished_at"` - // Whether the node is retired. A Node tagged as retired will prevent any further - // scheduling of instances, but will still allow for other operations, such as cleaning, to happen - Retired bool `json:"retired"` + // The UTC date and time when the resource was created, ISO 8601 format. + CreatedAt time.Time `json:"created_at"` - // Reason the node is marked as retired. - RetiredReason string `json:"retired_reason"` + // The UTC date and time when the resource was updated, ISO 8601 format. May be “null”. + UpdatedAt time.Time `json:"updated_at"` } // NodePage abstracts the raw results of making a List() request against diff --git a/openstack/baremetal/v1/nodes/testing/fixtures_test.go b/openstack/baremetal/v1/nodes/testing/fixtures_test.go index d47d70b13c..d174edde2b 100644 --- a/openstack/baremetal/v1/nodes/testing/fixtures_test.go +++ b/openstack/baremetal/v1/nodes/testing/fixtures_test.go @@ -925,23 +925,57 @@ var ( "deploy_ramdisk": "http://172.22.0.1/images/tinyipa-stable-rocky.gz", "ipmi_password": "admin", }, - DriverInternalInfo: map[string]any{}, - Properties: map[string]any{}, - InstanceInfo: map[string]any{}, - InstanceUUID: "", - ChassisUUID: "", - Extra: map[string]any{}, - ConsoleEnabled: false, - RAIDConfig: map[string]any{}, - TargetRAIDConfig: map[string]any{}, - CleanStep: map[string]any{}, - DeployStep: map[string]any{}, + DriverInternalInfo: map[string]any{}, + Properties: map[string]any{}, + InstanceInfo: map[string]any{}, + InstanceUUID: "", + ChassisUUID: "", + Extra: map[string]any{}, + ConsoleEnabled: false, + RAIDConfig: map[string]any{}, + TargetRAIDConfig: map[string]any{}, + CleanStep: map[string]any{}, + DeployStep: map[string]any{}, + Links: []nodes.Link{ + { + Href: "http://ironic.example.com:6385/v1/nodes/d2630783-6ec8-4836-b556-ab427c4b581e", + Rel: "self", + }, + { + Href: "http://ironic.example.com:6385/nodes/d2630783-6ec8-4836-b556-ab427c4b581e", + Rel: "bookmark", + }, + }, + Ports: []nodes.Link{ + { + Href: "http://ironic.example.com:6385/v1/nodes/d2630783-6ec8-4836-b556-ab427c4b581e/ports", + Rel: "self", + }, + { + Href: "http://ironic.example.com:6385/nodes/d2630783-6ec8-4836-b556-ab427c4b581e/ports", + Rel: "bookmark", + }, + }, + PortGroups: []nodes.Link{ + { + Href: "http://ironic.example.com:6385/v1/nodes/d2630783-6ec8-4836-b556-ab427c4b581e/portgroups", + Rel: "self", + }, + { + Href: "http://ironic.example.com:6385/nodes/d2630783-6ec8-4836-b556-ab427c4b581e/portgroups", + Rel: "bookmark"}, + }, + States: []nodes.Link{ + { + Href: "http://ironic.example.com:6385/v1/nodes/d2630783-6ec8-4836-b556-ab427c4b581e/states", + Rel: "self", + }, + }, ResourceClass: "", BIOSInterface: "no-bios", BootInterface: "pxe", ConsoleInterface: "no-console", DeployInterface: "iscsi", - FirmwareInterface: "no-firmware", InspectInterface: "no-inspect", ManagementInterface: "ipmitool", NetworkInterface: "flat", @@ -951,14 +985,33 @@ var ( StorageInterface: "noop", Traits: []string{}, VendorInterface: "ipmitool", - ConductorGroup: "", - Protected: false, - ProtectedReason: "", - CreatedAt: createdAtFoo, - UpdatedAt: updatedAt, - ProvisionUpdatedAt: provisonUpdatedAt, - Retired: false, - RetiredReason: "No longer needed", + Volume: []nodes.Link{ + { + Href: "http://ironic.example.com:6385/v1/nodes/d2630783-6ec8-4836-b556-ab427c4b581e/volume", + Rel: "self", + }, + }, + ConductorGroup: "", + ParentNode: "", + Protected: false, + ProtectedReason: "", + Owner: "", + Lessee: "", + Shard: "", + Description: "", + Conductor: "", + AllocationUUID: "", + Retired: false, + RetiredReason: "No longer needed", + NetworkData: map[string]interface{}(nil), + AutomatedClean: nil, + ServiceStep: map[string]interface{}(nil), + FirmwareInterface: "no-firmware", + ProvisionUpdatedAt: provisonUpdatedAt, + InspectionStartedAt: nil, + InspectionFinishedAt: nil, + CreatedAt: createdAtFoo, + UpdatedAt: updatedAt, } NodeFooValidation = nodes.NodeValidation{ @@ -1070,6 +1123,26 @@ var ( InspectionFinishedAt: &InspectionFinishedAt, Retired: false, RetiredReason: "No longer needed", + Links: []nodes.Link{ + {Href: "http://ironic.example.com:6385/v1/nodes/08c84581-58f5-4ea2-a0c6-dd2e5d2b3662", Rel: "self"}, + {Href: "http://ironic.example.com:6385/nodes/08c84581-58f5-4ea2-a0c6-dd2e5d2b3662", Rel: "bookmark"}, + }, + Ports: []nodes.Link{ + {Href: "http://ironic.example.com:6385/v1/nodes/08c84581-58f5-4ea2-a0c6-dd2e5d2b3662/ports", Rel: "self"}, + {Href: "http://ironic.example.com:6385/nodes/08c84581-58f5-4ea2-a0c6-dd2e5d2b3662/ports", Rel: "bookmark"}, + }, + PortGroups: []nodes.Link{ + {Href: "http://ironic.example.com:6385/v1/nodes/08c84581-58f5-4ea2-a0c6-dd2e5d2b3662/portgroups", Rel: "self"}, + {Href: "http://ironic.example.com:6385/nodes/08c84581-58f5-4ea2-a0c6-dd2e5d2b3662/portgroups", Rel: "bookmark"}, + }, + States: []nodes.Link{ + {Href: "http://ironic.example.com:6385/v1/nodes/08c84581-58f5-4ea2-a0c6-dd2e5d2b3662/states", Rel: "self"}, + {Href: "http://ironic.example.com:6385/nodes/08c84581-58f5-4ea2-a0c6-dd2e5d2b3662/states", Rel: "bookmark"}, + }, + Volume: []nodes.Link{ + {Href: "http://ironic.example.com:6385/v1/nodes/08c84581-58f5-4ea2-a0c6-dd2e5d2b3662/volume", Rel: "self"}, + {Href: "http://ironic.example.com:6385/nodes/08c84581-58f5-4ea2-a0c6-dd2e5d2b3662/volume", Rel: "bookmark"}, + }, } NodeBaz = nodes.Node{ @@ -1119,6 +1192,26 @@ var ( UpdatedAt: updatedAt, Retired: false, RetiredReason: "No longer needed", + Links: []nodes.Link{ + {Href: "http://ironic.example.com:6385/v1/nodes/c9afd385-5d89-4ecb-9e1c-68194da6b474", Rel: "self"}, + {Href: "http://ironic.example.com:6385/nodes/c9afd385-5d89-4ecb-9e1c-68194da6b474", Rel: "bookmark"}, + }, + Ports: []nodes.Link{ + {Href: "http://ironic.example.com:6385/v1/nodes/c9afd385-5d89-4ecb-9e1c-68194da6b474/ports", Rel: "self"}, + {Href: "http://ironic.example.com:6385/nodes/c9afd385-5d89-4ecb-9e1c-68194da6b474/ports", Rel: "bookmark"}, + }, + PortGroups: []nodes.Link{ + {Href: "http://ironic.example.com:6385/v1/nodes/c9afd385-5d89-4ecb-9e1c-68194da6b474/portgroups", Rel: "self"}, + {Href: "http://ironic.example.com:6385/nodes/c9afd385-5d89-4ecb-9e1c-68194da6b474/portgroups", Rel: "bookmark"}, + }, + States: []nodes.Link{ + {Href: "http://ironic.example.com:6385/v1/nodes/c9afd385-5d89-4ecb-9e1c-68194da6b474/states", Rel: "self"}, + {Href: "http://ironic.example.com:6385/nodes/c9afd385-5d89-4ecb-9e1c-68194da6b474/states", Rel: "bookmark"}, + }, + Volume: []nodes.Link{ + {Href: "http://ironic.example.com:6385/v1/nodes/c9afd385-5d89-4ecb-9e1c-68194da6b474/volume", Rel: "self"}, + {Href: "http://ironic.example.com:6385/nodes/c9afd385-5d89-4ecb-9e1c-68194da6b474/volume", Rel: "bookmark"}, + }, } ConfigDriveMap = nodes.ConfigDrive{ From 0d7a8655a2c49553d3f00454eedd0c91f07ca4d4 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 28 Nov 2024 17:58:30 +0000 Subject: [PATCH 055/429] Drop CI coverage for Antelope Antelope has entered the unmaintained [1] phase. We can no longer rely on this for testing. [1] https://docs.openstack.org/project-team-guide/stable-branches.html#unmaintained Signed-off-by: Stephen Finucane --- .github/workflows/functional-baremetal.yaml | 5 ----- .github/workflows/functional-basic.yaml | 4 ---- .github/workflows/functional-blockstorage.yaml | 4 ---- .github/workflows/functional-compute.yaml | 4 ---- .github/workflows/functional-containerinfra.yaml | 7 ------- .github/workflows/functional-dns.yaml | 4 ---- .github/workflows/functional-fwaas_v2.yaml | 4 ---- .github/workflows/functional-identity.yaml | 4 ---- .github/workflows/functional-image.yaml | 4 ---- .github/workflows/functional-keymanager.yaml | 4 ---- .github/workflows/functional-loadbalancer.yaml | 4 ---- .github/workflows/functional-messaging.yaml | 4 ---- .github/workflows/functional-networking.yaml | 4 ---- .github/workflows/functional-objectstorage.yaml | 4 ---- .github/workflows/functional-orchestration.yaml | 4 ---- .github/workflows/functional-placement.yaml | 4 ---- .github/workflows/functional-sharedfilesystems.yaml | 4 ---- 17 files changed, 72 deletions(-) diff --git a/.github/workflows/functional-baremetal.yaml b/.github/workflows/functional-baremetal.yaml index 2b9c24459e..ac2d37d6f2 100644 --- a/.github/workflows/functional-baremetal.yaml +++ b/.github/workflows/functional-baremetal.yaml @@ -34,11 +34,6 @@ jobs: ubuntu_version: "22.04" use_system_scope: false additional_services: "" - - name: "antelope" - openstack_version: "stable/2023.1" - ubuntu_version: "22.04" - use_system_scope: false - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Deploy OpenStack ${{ matrix.name }} with Ironic and run baremetal acceptance tests steps: diff --git a/.github/workflows/functional-basic.yaml b/.github/workflows/functional-basic.yaml index ec52a6a971..392ea1f06f 100644 --- a/.github/workflows/functional-basic.yaml +++ b/.github/workflows/functional-basic.yaml @@ -30,10 +30,6 @@ jobs: openstack_version: "stable/2023.2" ubuntu_version: "22.04" additional_services: "" - - name: "antelope" - openstack_version: "stable/2023.1" - ubuntu_version: "22.04" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Deploy OpenStack ${{ matrix.name }} with defaults and run basic acceptance tests steps: diff --git a/.github/workflows/functional-blockstorage.yaml b/.github/workflows/functional-blockstorage.yaml index a98ba4281b..c0b58484a7 100644 --- a/.github/workflows/functional-blockstorage.yaml +++ b/.github/workflows/functional-blockstorage.yaml @@ -27,10 +27,6 @@ jobs: openstack_version: "stable/2023.2" ubuntu_version: "22.04" additional_services: "" - - name: "antelope" - openstack_version: "stable/2023.1" - ubuntu_version: "22.04" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Deploy OpenStack ${{ matrix.name }} with Cinder and run blockstorage acceptance tests steps: diff --git a/.github/workflows/functional-compute.yaml b/.github/workflows/functional-compute.yaml index 158b1c4301..0ad2dfa8d6 100644 --- a/.github/workflows/functional-compute.yaml +++ b/.github/workflows/functional-compute.yaml @@ -27,10 +27,6 @@ jobs: openstack_version: "stable/2023.2" ubuntu_version: "22.04" additional_services: "" - - name: "antelope" - openstack_version: "stable/2023.1" - ubuntu_version: "22.04" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Deploy OpenStack ${{ matrix.name }} with Nova and run compute acceptance tests steps: diff --git a/.github/workflows/functional-containerinfra.yaml b/.github/workflows/functional-containerinfra.yaml index 45c1c95f53..a2ed183682 100644 --- a/.github/workflows/functional-containerinfra.yaml +++ b/.github/workflows/functional-containerinfra.yaml @@ -39,13 +39,6 @@ jobs: enable_plugin magnum https://github.com/openstack/magnum stable/2023.2 MAGNUMCLIENT_BRANCH=stable/2023.2 additional_services: "" - - name: "antelope" - openstack_version: "stable/2023.1" - ubuntu_version: "22.04" - devstack_conf_overrides: | - enable_plugin magnum https://github.com/openstack/magnum stable/2023.1 - MAGNUMCLIENT_BRANCH=stable/2023.1 - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Deploy OpenStack ${{ matrix.name }} with Magnum and run containerinfra acceptance tests steps: diff --git a/.github/workflows/functional-dns.yaml b/.github/workflows/functional-dns.yaml index 28392b4577..6b52023985 100644 --- a/.github/workflows/functional-dns.yaml +++ b/.github/workflows/functional-dns.yaml @@ -28,10 +28,6 @@ jobs: openstack_version: "stable/2023.2" ubuntu_version: "22.04" additional_services: "" - - name: "antelope" - openstack_version: "stable/2023.1" - ubuntu_version: "22.04" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Deploy OpenStack ${{ matrix.name }} with Designate and run dns acceptance tests steps: diff --git a/.github/workflows/functional-fwaas_v2.yaml b/.github/workflows/functional-fwaas_v2.yaml index 9b30f72220..d308ade3ed 100644 --- a/.github/workflows/functional-fwaas_v2.yaml +++ b/.github/workflows/functional-fwaas_v2.yaml @@ -27,10 +27,6 @@ jobs: openstack_version: "stable/2023.2" ubuntu_version: "22.04" additional_services: "" - - name: "antelope" - openstack_version: "stable/2023.1" - ubuntu_version: "22.04" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Deploy OpenStack ${{ matrix.name }} with enabled FWaaS_v2 and run networking acceptance tests steps: diff --git a/.github/workflows/functional-identity.yaml b/.github/workflows/functional-identity.yaml index badb239f9b..7a9d4ffaeb 100644 --- a/.github/workflows/functional-identity.yaml +++ b/.github/workflows/functional-identity.yaml @@ -27,10 +27,6 @@ jobs: openstack_version: "stable/2023.2" ubuntu_version: "22.04" additional_services: "" - - name: "antelope" - openstack_version: "stable/2023.1" - ubuntu_version: "22.04" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Deploy OpenStack ${{ matrix.name }} with Keystone and run identity acceptance tests steps: diff --git a/.github/workflows/functional-image.yaml b/.github/workflows/functional-image.yaml index e9192b1a7c..c6b956b882 100644 --- a/.github/workflows/functional-image.yaml +++ b/.github/workflows/functional-image.yaml @@ -27,10 +27,6 @@ jobs: openstack_version: "stable/2023.2" ubuntu_version: "22.04" additional_services: "" - - name: "antelope" - openstack_version: "stable/2023.1" - ubuntu_version: "22.04" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Deploy OpenStack ${{ matrix.name }} with Glance and run image acceptance tests steps: diff --git a/.github/workflows/functional-keymanager.yaml b/.github/workflows/functional-keymanager.yaml index 83245c0fe5..595a096697 100644 --- a/.github/workflows/functional-keymanager.yaml +++ b/.github/workflows/functional-keymanager.yaml @@ -27,10 +27,6 @@ jobs: openstack_version: "stable/2023.2" ubuntu_version: "22.04" additional_services: "" - - name: "antelope" - openstack_version: "stable/2023.1" - ubuntu_version: "22.04" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Deploy OpenStack ${{ matrix.name }} with Barbican and run keymanager acceptance tests steps: diff --git a/.github/workflows/functional-loadbalancer.yaml b/.github/workflows/functional-loadbalancer.yaml index 1069b530ca..11d67aef31 100644 --- a/.github/workflows/functional-loadbalancer.yaml +++ b/.github/workflows/functional-loadbalancer.yaml @@ -27,10 +27,6 @@ jobs: openstack_version: "stable/2023.2" ubuntu_version: "22.04" additional_services: "" - - name: "antelope" - openstack_version: "stable/2023.1" - ubuntu_version: "22.04" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Deploy OpenStack ${{ matrix.name }} with Octavia and run loadbalancer acceptance tests steps: diff --git a/.github/workflows/functional-messaging.yaml b/.github/workflows/functional-messaging.yaml index 711824957b..87c5b93ded 100644 --- a/.github/workflows/functional-messaging.yaml +++ b/.github/workflows/functional-messaging.yaml @@ -27,10 +27,6 @@ jobs: openstack_version: "stable/2023.2" ubuntu_version: "22.04" additional_services: "" - - name: "antelope" - openstack_version: "stable/2023.1" - ubuntu_version: "22.04" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Deploy OpenStack ${{ matrix.name }} with Zaqar and run messaging acceptance tests steps: diff --git a/.github/workflows/functional-networking.yaml b/.github/workflows/functional-networking.yaml index 0a9ff0b737..67ab119605 100644 --- a/.github/workflows/functional-networking.yaml +++ b/.github/workflows/functional-networking.yaml @@ -27,10 +27,6 @@ jobs: openstack_version: "stable/2023.2" ubuntu_version: "22.04" additional_services: "" - - name: "antelope" - openstack_version: "stable/2023.1" - ubuntu_version: "22.04" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Deploy OpenStack ${{ matrix.name }} with Neutron and run networking acceptance tests steps: diff --git a/.github/workflows/functional-objectstorage.yaml b/.github/workflows/functional-objectstorage.yaml index 76edde3d21..c71d17f372 100644 --- a/.github/workflows/functional-objectstorage.yaml +++ b/.github/workflows/functional-objectstorage.yaml @@ -27,10 +27,6 @@ jobs: openstack_version: "stable/2023.2" ubuntu_version: "22.04" additional_services: "" - - name: "antelope" - openstack_version: "stable/2023.1" - ubuntu_version: "22.04" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Deploy OpenStack ${{ matrix.name }} with Swift and run objectstorage acceptance tests steps: diff --git a/.github/workflows/functional-orchestration.yaml b/.github/workflows/functional-orchestration.yaml index 57344aa9ec..71213eea50 100644 --- a/.github/workflows/functional-orchestration.yaml +++ b/.github/workflows/functional-orchestration.yaml @@ -27,10 +27,6 @@ jobs: openstack_version: "stable/2023.2" ubuntu_version: "22.04" additional_services: "" - - name: "antelope" - openstack_version: "stable/2023.1" - ubuntu_version: "22.04" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Deploy OpenStack ${{ matrix.name }} with Heat and run orchestration acceptance tests steps: diff --git a/.github/workflows/functional-placement.yaml b/.github/workflows/functional-placement.yaml index 566eba1642..15982c5318 100644 --- a/.github/workflows/functional-placement.yaml +++ b/.github/workflows/functional-placement.yaml @@ -27,10 +27,6 @@ jobs: openstack_version: "stable/2023.2" ubuntu_version: "22.04" additional_services: "" - - name: "antelope" - openstack_version: "stable/2023.1" - ubuntu_version: "22.04" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Deploy OpenStack ${{ matrix.name }} with Placement and run placement acceptance tests steps: diff --git a/.github/workflows/functional-sharedfilesystems.yaml b/.github/workflows/functional-sharedfilesystems.yaml index 59f442b341..d2702759a5 100644 --- a/.github/workflows/functional-sharedfilesystems.yaml +++ b/.github/workflows/functional-sharedfilesystems.yaml @@ -27,10 +27,6 @@ jobs: openstack_version: "stable/2023.2" ubuntu_version: "22.04" additional_services: "" - - name: "antelope" - openstack_version: "stable/2023.1" - ubuntu_version: "22.04" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Deploy OpenStack ${{ matrix.name }} with Manila and run sharedfilesystems acceptance tests steps: From 37efb25177ce9a88c9fa3d298eb615e116fadcb6 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Wed, 29 May 2024 14:46:10 +0100 Subject: [PATCH 056/429] make: Add 'format' target Signed-off-by: Stephen Finucane --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile b/Makefile index 128beec005..4298ae0e2a 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,10 @@ lint: golangci/golangci-lint:$(GOLANGCI_LINT_VERSION) golangci-lint run .PHONY: lint +format: + gofmt -w -s $(shell pwd) +.PHONY: format + unit: go test ./... .PHONY: unit From 2e647143a83375272a543f4300562710da444409 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 28 Nov 2024 13:49:00 +0000 Subject: [PATCH 057/429] script: Remove unused bootstrap script This is not referenced or documented anywhere and it has not been touched in years. Remove it. Signed-off-by: Stephen Finucane --- script/bootstrap | 25 ------------------------- 1 file changed, 25 deletions(-) delete mode 100755 script/bootstrap diff --git a/script/bootstrap b/script/bootstrap deleted file mode 100755 index 78a195dcf7..0000000000 --- a/script/bootstrap +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -# -# This script helps new contributors set up their local workstation for -# gophercloud development and contributions. - -# Create the environment -export GOPATH=$HOME/go/gophercloud -mkdir -p $GOPATH - -# Download gophercloud into that environment -go get github.com/gophercloud/gophercloud -cd $GOPATH/src/github.com/gophercloud/gophercloud -git checkout master - -# Write out the env.sh convenience file. -cd $GOPATH -cat <env.sh -#!/bin/bash -export GOPATH=$(pwd) -export GOPHERCLOUD=$GOPATH/src/github.com/gophercloud/gophercloud -EOF -chmod a+x env.sh - -# Make changes immediately available as a convenience. -. ./env.sh From baa5df96941191c7875826f577d9676579bec9e7 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Wed, 20 Mar 2024 13:31:11 +0000 Subject: [PATCH 058/429] trivial: Consistent file extensions Signed-off-by: Stephen Finucane --- .github/{dependabot.yml => dependabot.yaml} | 0 .github/workflows/{codeql-analysis.yml => codeql-analysis.yaml} | 0 .github/workflows/{greetings.yml => greetings.yaml} | 0 .github/workflows/{unit.yml => unit.yaml} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename .github/{dependabot.yml => dependabot.yaml} (100%) rename .github/workflows/{codeql-analysis.yml => codeql-analysis.yaml} (100%) rename .github/workflows/{greetings.yml => greetings.yaml} (100%) rename .github/workflows/{unit.yml => unit.yaml} (100%) diff --git a/.github/dependabot.yml b/.github/dependabot.yaml similarity index 100% rename from .github/dependabot.yml rename to .github/dependabot.yaml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yaml similarity index 100% rename from .github/workflows/codeql-analysis.yml rename to .github/workflows/codeql-analysis.yaml diff --git a/.github/workflows/greetings.yml b/.github/workflows/greetings.yaml similarity index 100% rename from .github/workflows/greetings.yml rename to .github/workflows/greetings.yaml diff --git a/.github/workflows/unit.yml b/.github/workflows/unit.yaml similarity index 100% rename from .github/workflows/unit.yml rename to .github/workflows/unit.yaml From 65463f13d5b57aad057642b9bb42d3b62291afef Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 21 Mar 2024 12:23:28 +0000 Subject: [PATCH 059/429] script: Address shellcheck warnings Signed-off-by: Stephen Finucane --- script/acceptancetest | 9 +++++---- script/coverage | 3 ++- script/test | 1 + script/unittest | 1 + script/vet | 2 +- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/script/acceptancetest b/script/acceptancetest index 234f5b0bb6..7e223bae5e 100755 --- a/script/acceptancetest +++ b/script/acceptancetest @@ -7,19 +7,20 @@ # flags and things crash and burn *spectacularly* 🔥🔥🔥 set -xo pipefail -source $(dirname $0)/stackenv +# shellcheck disable=SC1091 +source "$(dirname "$0")/stackenv" # ...but we can do it after the fact set -eu timeout="60m" -failed= LOG_DIR=${LOG_DIR:-} if [[ -z "${LOG_DIR}" ]]; then echo "LOG_DIR not set, will set a temp directory" LOG_DIR=/tmp/devstack-logs fi -mkdir -p ${LOG_DIR} +mkdir -p "${LOG_DIR}" -go test -v -timeout $timeout -tags "fixtures acceptance" ${PACKAGE:-./internal/acceptance/openstack/...} $@ |& tee -a ${LOG_DIR}/acceptance_tests.log +# shellcheck disable=SC2068 +go test -v -timeout $timeout -tags "fixtures acceptance" "${PACKAGE:-./internal/acceptance/openstack/...}" $@ |& tee -a "${LOG_DIR}/acceptance_tests.log" diff --git a/script/coverage b/script/coverage index cd4dec06e5..ec5b2776b8 100755 --- a/script/coverage +++ b/script/coverage @@ -19,5 +19,6 @@ for path in $(find . -path '*/testing' -prune -o -path '*/internal' -prune -o -n n=$((n+1)) done -gocovmerge `ls *.coverprofile` > cover.out +# shellcheck disable=SC2046 +gocovmerge $(ls -- *.coverprofile) > cover.out rm ./*.coverprofile diff --git a/script/test b/script/test index 77f6af5017..e71e7514bb 100755 --- a/script/test +++ b/script/test @@ -4,4 +4,5 @@ set -euxo pipefail +# shellcheck disable=SC2068 go test -v -tags 'acceptance fixtures' ./... $@ diff --git a/script/unittest b/script/unittest index 2763e0efd9..1f1b1864f4 100755 --- a/script/unittest +++ b/script/unittest @@ -6,4 +6,5 @@ set -euxo pipefail # Do extra rounds of testing to help identify reauth concurrency issues. # All other packages are tested in the `coverage` tests. +# shellcheck disable=SC2068 go test -v -race -count=5 ./testing $@ diff --git a/script/vet b/script/vet index 4f3db40a28..ecb74ef37d 100755 --- a/script/vet +++ b/script/vet @@ -4,5 +4,5 @@ set -euxo pipefail -GOFLAGS="-tags=acceptance" +export GOFLAGS="-tags=acceptance" go vet ./... From 67c72f8db8b971305971fc9d1ec808fffc094011 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 30 May 2024 23:51:52 +0100 Subject: [PATCH 060/429] tests: Consist use of th alias testhelper is too long give how often these things are used. Signed-off-by: Stephen Finucane --- .../v1/nodes/testing/results_test.go | 50 +++---- .../schedulerstats/testing/fixtures_test.go | 8 +- .../schedulerstats/testing/requests_test.go | 14 +- .../v2/services/testing/requests_test.go | 14 +- .../schedulerstats/testing/fixtures_test.go | 8 +- .../schedulerstats/testing/requests_test.go | 14 +- .../v3/services/testing/requests_test.go | 14 +- .../v2/hypervisors/testing/fixtures_test.go | 52 +++---- .../v2/hypervisors/testing/requests_test.go | 98 ++++++------- .../v2/services/testing/requests_test.go | 42 +++--- .../v3/ec2tokens/testing/requests_test.go | 36 ++--- .../v3/oauth1/testing/fixtures_test.go | 136 +++++++++--------- .../identity/v3/tokens/testing/fixtures.go | 6 +- .../v3/tokens/testing/requests_test.go | 118 +++++++-------- .../v3/tokens/testing/results_test.go | 26 ++-- .../v3/trusts/testing/fixtures_test.go | 68 ++++----- .../schedulerstats/testing/fixtures_test.go | 14 +- .../schedulerstats/testing/requests_test.go | 30 ++-- .../v2/services/testing/requests_test.go | 12 +- .../utils/testing/choose_version_test.go | 66 ++++----- pagination/testing/linked_test.go | 26 ++-- pagination/testing/marker_test.go | 24 ++-- pagination/testing/pagination_test.go | 4 +- pagination/testing/single_test.go | 26 ++-- testhelper/client/fake.go | 4 +- 25 files changed, 455 insertions(+), 455 deletions(-) diff --git a/openstack/baremetal/v1/nodes/testing/results_test.go b/openstack/baremetal/v1/nodes/testing/results_test.go index 7c683ebecb..acdb59e774 100644 --- a/openstack/baremetal/v1/nodes/testing/results_test.go +++ b/openstack/baremetal/v1/nodes/testing/results_test.go @@ -8,68 +8,68 @@ import ( "github.com/gophercloud/gophercloud/v2/openstack/baremetal/v1/nodes" "github.com/gophercloud/gophercloud/v2/openstack/baremetalintrospection/v1/introspection" insptest "github.com/gophercloud/gophercloud/v2/openstack/baremetalintrospection/v1/introspection/testing" - "github.com/gophercloud/gophercloud/v2/testhelper" + th "github.com/gophercloud/gophercloud/v2/testhelper" ) func TestStandardPluginData(t *testing.T) { var pluginData nodes.PluginData err := pluginData.RawMessage.UnmarshalJSON([]byte(invtest.StandardPluginDataSample)) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) parsedData, err := pluginData.AsStandardData() - testhelper.AssertNoErr(t, err) - testhelper.CheckDeepEquals(t, invtest.StandardPluginData, parsedData) + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, invtest.StandardPluginData, parsedData) irData, inspData, err := pluginData.GuessFormat() - testhelper.AssertNoErr(t, err) - testhelper.CheckDeepEquals(t, invtest.StandardPluginData, *irData) - testhelper.CheckEquals(t, (*introspection.Data)(nil), inspData) + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, invtest.StandardPluginData, *irData) + th.CheckEquals(t, (*introspection.Data)(nil), inspData) } func TestInspectorPluginData(t *testing.T) { var pluginData nodes.PluginData err := pluginData.RawMessage.UnmarshalJSON([]byte(insptest.IntrospectionDataJSONSample)) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) parsedData, err := pluginData.AsInspectorData() - testhelper.AssertNoErr(t, err) - testhelper.CheckDeepEquals(t, insptest.IntrospectionDataRes, parsedData) + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, insptest.IntrospectionDataRes, parsedData) irData, inspData, err := pluginData.GuessFormat() - testhelper.AssertNoErr(t, err) - testhelper.CheckEquals(t, (*inventory.StandardPluginData)(nil), irData) - testhelper.CheckDeepEquals(t, insptest.IntrospectionDataRes, *inspData) + th.AssertNoErr(t, err) + th.CheckEquals(t, (*inventory.StandardPluginData)(nil), irData) + th.CheckDeepEquals(t, insptest.IntrospectionDataRes, *inspData) } func TestGuessFormatUnknownDefaultsToIronic(t *testing.T) { var pluginData nodes.PluginData err := pluginData.RawMessage.UnmarshalJSON([]byte("{}")) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) irData, inspData, err := pluginData.GuessFormat() - testhelper.CheckDeepEquals(t, inventory.StandardPluginData{}, *irData) - testhelper.CheckEquals(t, (*introspection.Data)(nil), inspData) - testhelper.AssertNoErr(t, err) + th.CheckDeepEquals(t, inventory.StandardPluginData{}, *irData) + th.CheckEquals(t, (*introspection.Data)(nil), inspData) + th.AssertNoErr(t, err) } func TestGuessFormatErrors(t *testing.T) { var pluginData nodes.PluginData err := pluginData.RawMessage.UnmarshalJSON([]byte("\"banana\"")) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) irData, inspData, err := pluginData.GuessFormat() - testhelper.CheckEquals(t, (*inventory.StandardPluginData)(nil), irData) - testhelper.CheckEquals(t, (*introspection.Data)(nil), inspData) - testhelper.AssertErr(t, err) + th.CheckEquals(t, (*inventory.StandardPluginData)(nil), irData) + th.CheckEquals(t, (*introspection.Data)(nil), inspData) + th.AssertErr(t, err) failsInspectorConversion := `{ "interfaces": "banana" }` err = pluginData.RawMessage.UnmarshalJSON([]byte(failsInspectorConversion)) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) irData, inspData, err = pluginData.GuessFormat() - testhelper.CheckEquals(t, (*inventory.StandardPluginData)(nil), irData) - testhelper.CheckEquals(t, (*introspection.Data)(nil), inspData) - testhelper.AssertErr(t, err) + th.CheckEquals(t, (*inventory.StandardPluginData)(nil), irData) + th.CheckEquals(t, (*introspection.Data)(nil), inspData) + th.AssertErr(t, err) } diff --git a/openstack/blockstorage/v2/schedulerstats/testing/fixtures_test.go b/openstack/blockstorage/v2/schedulerstats/testing/fixtures_test.go index 6f0317ef60..3a7fee8160 100644 --- a/openstack/blockstorage/v2/schedulerstats/testing/fixtures_test.go +++ b/openstack/blockstorage/v2/schedulerstats/testing/fixtures_test.go @@ -7,7 +7,7 @@ import ( "testing" "github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v2/schedulerstats" - "github.com/gophercloud/gophercloud/v2/testhelper" + th "github.com/gophercloud/gophercloud/v2/testhelper" "github.com/gophercloud/gophercloud/v2/testhelper/client" ) @@ -94,9 +94,9 @@ var ( ) func HandleStoragePoolsListSuccessfully(t *testing.T) { - testhelper.Mux.HandleFunc("/scheduler-stats/get_pools", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "GET") - testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.Mux.HandleFunc("/scheduler-stats/get_pools", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") diff --git a/openstack/blockstorage/v2/schedulerstats/testing/requests_test.go b/openstack/blockstorage/v2/schedulerstats/testing/requests_test.go index 709ddeac58..7a6cb8b450 100644 --- a/openstack/blockstorage/v2/schedulerstats/testing/requests_test.go +++ b/openstack/blockstorage/v2/schedulerstats/testing/requests_test.go @@ -6,13 +6,13 @@ import ( "github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v2/schedulerstats" "github.com/gophercloud/gophercloud/v2/pagination" - "github.com/gophercloud/gophercloud/v2/testhelper" + th "github.com/gophercloud/gophercloud/v2/testhelper" "github.com/gophercloud/gophercloud/v2/testhelper/client" ) func TestListStoragePoolsDetail(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() HandleStoragePoolsListSuccessfully(t) pages := 0 @@ -20,18 +20,18 @@ func TestListStoragePoolsDetail(t *testing.T) { pages++ actual, err := schedulerstats.ExtractStoragePools(page) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) if len(actual) != 2 { t.Fatalf("Expected 2 backends, got %d", len(actual)) } - testhelper.CheckDeepEquals(t, StoragePoolFake1, actual[0]) - testhelper.CheckDeepEquals(t, StoragePoolFake2, actual[1]) + th.CheckDeepEquals(t, StoragePoolFake1, actual[0]) + th.CheckDeepEquals(t, StoragePoolFake2, actual[1]) return true, nil }) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) if pages != 1 { t.Errorf("Expected 1 page, saw %d", pages) diff --git a/openstack/blockstorage/v2/services/testing/requests_test.go b/openstack/blockstorage/v2/services/testing/requests_test.go index 8ce1266d7e..d1277a99bf 100644 --- a/openstack/blockstorage/v2/services/testing/requests_test.go +++ b/openstack/blockstorage/v2/services/testing/requests_test.go @@ -6,13 +6,13 @@ import ( "github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v2/services" "github.com/gophercloud/gophercloud/v2/pagination" - "github.com/gophercloud/gophercloud/v2/testhelper" + th "github.com/gophercloud/gophercloud/v2/testhelper" "github.com/gophercloud/gophercloud/v2/testhelper/client" ) func TestListServices(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() HandleListSuccessfully(t) pages := 0 @@ -27,14 +27,14 @@ func TestListServices(t *testing.T) { if len(actual) != 3 { t.Fatalf("Expected 3 services, got %d", len(actual)) } - testhelper.CheckDeepEquals(t, FirstFakeService, actual[0]) - testhelper.CheckDeepEquals(t, SecondFakeService, actual[1]) - testhelper.CheckDeepEquals(t, ThirdFakeService, actual[2]) + th.CheckDeepEquals(t, FirstFakeService, actual[0]) + th.CheckDeepEquals(t, SecondFakeService, actual[1]) + th.CheckDeepEquals(t, ThirdFakeService, actual[2]) return true, nil }) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) if pages != 1 { t.Errorf("Expected 1 page, saw %d", pages) diff --git a/openstack/blockstorage/v3/schedulerstats/testing/fixtures_test.go b/openstack/blockstorage/v3/schedulerstats/testing/fixtures_test.go index df0ccaa7f5..0a1286e862 100644 --- a/openstack/blockstorage/v3/schedulerstats/testing/fixtures_test.go +++ b/openstack/blockstorage/v3/schedulerstats/testing/fixtures_test.go @@ -7,7 +7,7 @@ import ( "testing" "github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/schedulerstats" - "github.com/gophercloud/gophercloud/v2/testhelper" + th "github.com/gophercloud/gophercloud/v2/testhelper" "github.com/gophercloud/gophercloud/v2/testhelper/client" ) @@ -94,9 +94,9 @@ var ( ) func HandleStoragePoolsListSuccessfully(t *testing.T) { - testhelper.Mux.HandleFunc("/scheduler-stats/get_pools", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "GET") - testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.Mux.HandleFunc("/scheduler-stats/get_pools", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") diff --git a/openstack/blockstorage/v3/schedulerstats/testing/requests_test.go b/openstack/blockstorage/v3/schedulerstats/testing/requests_test.go index b5e3f31ef6..c125763276 100644 --- a/openstack/blockstorage/v3/schedulerstats/testing/requests_test.go +++ b/openstack/blockstorage/v3/schedulerstats/testing/requests_test.go @@ -6,13 +6,13 @@ import ( "github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/schedulerstats" "github.com/gophercloud/gophercloud/v2/pagination" - "github.com/gophercloud/gophercloud/v2/testhelper" + th "github.com/gophercloud/gophercloud/v2/testhelper" "github.com/gophercloud/gophercloud/v2/testhelper/client" ) func TestListStoragePoolsDetail(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() HandleStoragePoolsListSuccessfully(t) pages := 0 @@ -20,18 +20,18 @@ func TestListStoragePoolsDetail(t *testing.T) { pages++ actual, err := schedulerstats.ExtractStoragePools(page) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) if len(actual) != 2 { t.Fatalf("Expected 2 backends, got %d", len(actual)) } - testhelper.CheckDeepEquals(t, StoragePoolFake1, actual[0]) - testhelper.CheckDeepEquals(t, StoragePoolFake2, actual[1]) + th.CheckDeepEquals(t, StoragePoolFake1, actual[0]) + th.CheckDeepEquals(t, StoragePoolFake2, actual[1]) return true, nil }) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) if pages != 1 { t.Errorf("Expected 1 page, saw %d", pages) diff --git a/openstack/blockstorage/v3/services/testing/requests_test.go b/openstack/blockstorage/v3/services/testing/requests_test.go index 1fd5bcdd1e..4e291da96b 100644 --- a/openstack/blockstorage/v3/services/testing/requests_test.go +++ b/openstack/blockstorage/v3/services/testing/requests_test.go @@ -6,13 +6,13 @@ import ( "github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/services" "github.com/gophercloud/gophercloud/v2/pagination" - "github.com/gophercloud/gophercloud/v2/testhelper" + th "github.com/gophercloud/gophercloud/v2/testhelper" "github.com/gophercloud/gophercloud/v2/testhelper/client" ) func TestListServices(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() HandleListSuccessfully(t) pages := 0 @@ -27,14 +27,14 @@ func TestListServices(t *testing.T) { if len(actual) != 3 { t.Fatalf("Expected 3 services, got %d", len(actual)) } - testhelper.CheckDeepEquals(t, FirstFakeService, actual[0]) - testhelper.CheckDeepEquals(t, SecondFakeService, actual[1]) - testhelper.CheckDeepEquals(t, ThirdFakeService, actual[2]) + th.CheckDeepEquals(t, FirstFakeService, actual[0]) + th.CheckDeepEquals(t, SecondFakeService, actual[1]) + th.CheckDeepEquals(t, ThirdFakeService, actual[2]) return true, nil }) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) if pages != 1 { t.Errorf("Expected 1 page, saw %d", pages) diff --git a/openstack/compute/v2/hypervisors/testing/fixtures_test.go b/openstack/compute/v2/hypervisors/testing/fixtures_test.go index a969f1f825..6e4b2e4aff 100644 --- a/openstack/compute/v2/hypervisors/testing/fixtures_test.go +++ b/openstack/compute/v2/hypervisors/testing/fixtures_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/gophercloud/gophercloud/v2/openstack/compute/v2/hypervisors" - "github.com/gophercloud/gophercloud/v2/testhelper" + th "github.com/gophercloud/gophercloud/v2/testhelper" "github.com/gophercloud/gophercloud/v2/testhelper/client" ) @@ -600,9 +600,9 @@ var ( ) func HandleHypervisorsStatisticsSuccessfully(t *testing.T) { - testhelper.Mux.HandleFunc("/os-hypervisors/statistics", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "GET") - testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.Mux.HandleFunc("/os-hypervisors/statistics", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") fmt.Fprintf(w, HypervisorsStatisticsBody) @@ -610,9 +610,9 @@ func HandleHypervisorsStatisticsSuccessfully(t *testing.T) { } func HandleHypervisorListPre253Successfully(t *testing.T) { - testhelper.Mux.HandleFunc("/os-hypervisors/detail", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "GET") - testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.Mux.HandleFunc("/os-hypervisors/detail", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") fmt.Fprintf(w, HypervisorListBodyPre253) @@ -620,9 +620,9 @@ func HandleHypervisorListPre253Successfully(t *testing.T) { } func HandleHypervisorListSuccessfully(t *testing.T) { - testhelper.Mux.HandleFunc("/os-hypervisors/detail", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "GET") - testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.Mux.HandleFunc("/os-hypervisors/detail", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") fmt.Fprintf(w, HypervisorListBody) @@ -630,10 +630,10 @@ func HandleHypervisorListSuccessfully(t *testing.T) { } func HandleHypervisorListWithParametersSuccessfully(t *testing.T) { - testhelper.Mux.HandleFunc("/os-hypervisors/detail", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "GET") - testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID) - testhelper.TestFormValues(t, r, map[string]string{ + th.Mux.HandleFunc("/os-hypervisors/detail", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.TestFormValues(t, r, map[string]string{ "with_servers": "true", }) @@ -643,9 +643,9 @@ func HandleHypervisorListWithParametersSuccessfully(t *testing.T) { } func HandleHypervisorGetSuccessfully(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) + th.Mux.HandleFunc("/os-hypervisors/"+HypervisorFake.ID, func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") fmt.Fprintf(w, HypervisorGetBody) @@ -653,9 +653,9 @@ func HandleHypervisorGetSuccessfully(t *testing.T) { } func HandleHypervisorGetEmptyCPUInfoSuccessfully(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) + th.Mux.HandleFunc("/os-hypervisors/"+HypervisorFake.ID, func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") fmt.Fprintf(w, HypervisorGetEmptyCPUInfoBody) @@ -663,9 +663,9 @@ 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) + th.Mux.HandleFunc("/os-hypervisors/"+HypervisorFake.ID, func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") fmt.Fprintf(w, HypervisorAfterV287ResponseBody) @@ -673,9 +673,9 @@ func HandleHypervisorAfterV287ResponseSuccessfully(t *testing.T) { } 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") - testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.Mux.HandleFunc("/os-hypervisors/"+HypervisorFake.ID+"/uptime", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") fmt.Fprintf(w, HypervisorUptimeBody) diff --git a/openstack/compute/v2/hypervisors/testing/requests_test.go b/openstack/compute/v2/hypervisors/testing/requests_test.go index 493e8138d1..0303f7f1d0 100644 --- a/openstack/compute/v2/hypervisors/testing/requests_test.go +++ b/openstack/compute/v2/hypervisors/testing/requests_test.go @@ -6,13 +6,13 @@ import ( "github.com/gophercloud/gophercloud/v2/openstack/compute/v2/hypervisors" "github.com/gophercloud/gophercloud/v2/pagination" - "github.com/gophercloud/gophercloud/v2/testhelper" + th "github.com/gophercloud/gophercloud/v2/testhelper" "github.com/gophercloud/gophercloud/v2/testhelper/client" ) func TestListHypervisorsPre253(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() HandleHypervisorListPre253Successfully(t) pages := 0 @@ -28,13 +28,13 @@ func TestListHypervisorsPre253(t *testing.T) { if len(actual) != 2 { t.Fatalf("Expected 2 hypervisors, got %d", len(actual)) } - testhelper.CheckDeepEquals(t, HypervisorFakePre253, actual[0]) - testhelper.CheckDeepEquals(t, HypervisorFakePre253, actual[1]) + th.CheckDeepEquals(t, HypervisorFakePre253, actual[0]) + th.CheckDeepEquals(t, HypervisorFakePre253, actual[1]) return true, nil }) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) if pages != 1 { t.Errorf("Expected 1 page, saw %d", pages) @@ -42,21 +42,21 @@ func TestListHypervisorsPre253(t *testing.T) { } func TestListAllHypervisorsPre253(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() HandleHypervisorListPre253Successfully(t) allPages, err := hypervisors.List(client.ServiceClient(), hypervisors.ListOpts{}).AllPages(context.TODO()) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) actual, err := hypervisors.ExtractHypervisors(allPages) - testhelper.AssertNoErr(t, err) - testhelper.CheckDeepEquals(t, HypervisorFakePre253, actual[0]) - testhelper.CheckDeepEquals(t, HypervisorFakePre253, actual[1]) + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, HypervisorFakePre253, actual[0]) + th.CheckDeepEquals(t, HypervisorFakePre253, actual[1]) } func TestListHypervisors(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() HandleHypervisorListSuccessfully(t) pages := 0 @@ -72,13 +72,13 @@ func TestListHypervisors(t *testing.T) { if len(actual) != 2 { t.Fatalf("Expected 2 hypervisors, got %d", len(actual)) } - testhelper.CheckDeepEquals(t, HypervisorFake, actual[0]) - testhelper.CheckDeepEquals(t, HypervisorFake, actual[1]) + th.CheckDeepEquals(t, HypervisorFake, actual[0]) + th.CheckDeepEquals(t, HypervisorFake, actual[1]) return true, nil }) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) if pages != 1 { t.Errorf("Expected 1 page, saw %d", pages) @@ -86,88 +86,88 @@ func TestListHypervisors(t *testing.T) { } func TestListAllHypervisors(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() HandleHypervisorListSuccessfully(t) allPages, err := hypervisors.List(client.ServiceClient(), hypervisors.ListOpts{}).AllPages(context.TODO()) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) actual, err := hypervisors.ExtractHypervisors(allPages) - testhelper.AssertNoErr(t, err) - testhelper.CheckDeepEquals(t, HypervisorFake, actual[0]) - testhelper.CheckDeepEquals(t, HypervisorFake, actual[1]) + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, HypervisorFake, actual[0]) + th.CheckDeepEquals(t, HypervisorFake, actual[1]) } func TestListAllHypervisorsWithParameters(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() HandleHypervisorListWithParametersSuccessfully(t) with_servers := true allPages, err := hypervisors.List(client.ServiceClient(), hypervisors.ListOpts{WithServers: &with_servers}).AllPages(context.TODO()) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) actual, err := hypervisors.ExtractHypervisors(allPages) - testhelper.AssertNoErr(t, err) - testhelper.CheckDeepEquals(t, HypervisorFakeWithParameters, actual[0]) - testhelper.CheckDeepEquals(t, HypervisorFakeWithParameters, actual[1]) + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, HypervisorFakeWithParameters, actual[0]) + th.CheckDeepEquals(t, HypervisorFakeWithParameters, actual[1]) } func TestHypervisorsStatistics(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() HandleHypervisorsStatisticsSuccessfully(t) expected := HypervisorsStatisticsExpected actual, err := hypervisors.GetStatistics(context.TODO(), client.ServiceClient()).Extract() - testhelper.AssertNoErr(t, err) - testhelper.CheckDeepEquals(t, &expected, actual) + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, &expected, actual) } func TestGetHypervisor(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() HandleHypervisorGetSuccessfully(t) expected := HypervisorFake actual, err := hypervisors.Get(context.TODO(), client.ServiceClient(), expected.ID).Extract() - testhelper.AssertNoErr(t, err) - testhelper.CheckDeepEquals(t, &expected, actual) + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, &expected, actual) } func TestGetHypervisorEmptyCPUInfo(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() HandleHypervisorGetEmptyCPUInfoSuccessfully(t) expected := HypervisorEmptyCPUInfo actual, err := hypervisors.Get(context.TODO(), client.ServiceClient(), expected.ID).Extract() - testhelper.AssertNoErr(t, err) - testhelper.CheckDeepEquals(t, &expected, actual) + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, &expected, actual) } func TestGetHypervisorAfterV287Response(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.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) + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, &expected, actual) } func TestHypervisorsUptime(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() HandleHypervisorUptimeSuccessfully(t) expected := HypervisorUptimeExpected actual, err := hypervisors.GetUptime(context.TODO(), client.ServiceClient(), HypervisorFake.ID).Extract() - testhelper.AssertNoErr(t, err) - testhelper.CheckDeepEquals(t, &expected, actual) + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, &expected, actual) } diff --git a/openstack/compute/v2/services/testing/requests_test.go b/openstack/compute/v2/services/testing/requests_test.go index c201c9f4d6..df7a9e9a17 100644 --- a/openstack/compute/v2/services/testing/requests_test.go +++ b/openstack/compute/v2/services/testing/requests_test.go @@ -6,13 +6,13 @@ import ( "github.com/gophercloud/gophercloud/v2/openstack/compute/v2/services" "github.com/gophercloud/gophercloud/v2/pagination" - "github.com/gophercloud/gophercloud/v2/testhelper" + th "github.com/gophercloud/gophercloud/v2/testhelper" "github.com/gophercloud/gophercloud/v2/testhelper/client" ) func TestListServicesPre253(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() HandleListPre253Successfully(t) pages := 0 @@ -27,15 +27,15 @@ func TestListServicesPre253(t *testing.T) { if len(actual) != 4 { t.Fatalf("Expected 4 services, got %d", len(actual)) } - testhelper.CheckDeepEquals(t, FirstFakeServicePre253, actual[0]) - testhelper.CheckDeepEquals(t, SecondFakeServicePre253, actual[1]) - testhelper.CheckDeepEquals(t, ThirdFakeServicePre253, actual[2]) - testhelper.CheckDeepEquals(t, FourthFakeServicePre253, actual[3]) + th.CheckDeepEquals(t, FirstFakeServicePre253, actual[0]) + th.CheckDeepEquals(t, SecondFakeServicePre253, actual[1]) + th.CheckDeepEquals(t, ThirdFakeServicePre253, actual[2]) + th.CheckDeepEquals(t, FourthFakeServicePre253, actual[3]) return true, nil }) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) if pages != 1 { t.Errorf("Expected 1 page, saw %d", pages) @@ -43,8 +43,8 @@ func TestListServicesPre253(t *testing.T) { } func TestListServices(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() HandleListSuccessfully(t) pages := 0 @@ -63,15 +63,15 @@ func TestListServices(t *testing.T) { if len(actual) != 4 { t.Fatalf("Expected 4 services, got %d", len(actual)) } - testhelper.CheckDeepEquals(t, FirstFakeService, actual[0]) - testhelper.CheckDeepEquals(t, SecondFakeService, actual[1]) - testhelper.CheckDeepEquals(t, ThirdFakeService, actual[2]) - testhelper.CheckDeepEquals(t, FourthFakeService, actual[3]) + th.CheckDeepEquals(t, FirstFakeService, actual[0]) + th.CheckDeepEquals(t, SecondFakeService, actual[1]) + th.CheckDeepEquals(t, ThirdFakeService, actual[2]) + th.CheckDeepEquals(t, FourthFakeService, actual[3]) return true, nil }) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) if pages != 1 { t.Errorf("Expected 1 page, saw %d", pages) @@ -79,8 +79,8 @@ func TestListServices(t *testing.T) { } func TestUpdateService(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() HandleUpdateSuccessfully(t) client := client.ServiceClient() @@ -89,16 +89,16 @@ func TestUpdateService(t *testing.T) { t.Fatalf("Unexpected Update error: %v", err) } - testhelper.CheckDeepEquals(t, FakeServiceUpdateBody, *actual) + th.CheckDeepEquals(t, FakeServiceUpdateBody, *actual) } func TestDeleteService(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() HandleDeleteSuccessfully(t) client := client.ServiceClient() res := services.Delete(context.TODO(), client, "fake-service-id") - testhelper.AssertNoErr(t, res.Err) + th.AssertNoErr(t, res.Err) } diff --git a/openstack/identity/v3/ec2tokens/testing/requests_test.go b/openstack/identity/v3/ec2tokens/testing/requests_test.go index 188329daab..13239e2d91 100644 --- a/openstack/identity/v3/ec2tokens/testing/requests_test.go +++ b/openstack/identity/v3/ec2tokens/testing/requests_test.go @@ -12,24 +12,24 @@ import ( "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/ec2tokens" "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/tokens" tokens_testing "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/tokens/testing" - "github.com/gophercloud/gophercloud/v2/testhelper" + th "github.com/gophercloud/gophercloud/v2/testhelper" ) // authTokenPost verifies that providing certain AuthOptions and Scope results in an expected JSON structure. func authTokenPost(t *testing.T, options ec2tokens.AuthOptions, requestJSON string) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() client := gophercloud.ServiceClient{ ProviderClient: &gophercloud.ProviderClient{}, - Endpoint: testhelper.Endpoint(), + Endpoint: th.Endpoint(), } - testhelper.Mux.HandleFunc("/ec2tokens", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "POST") - testhelper.TestHeader(t, r, "Content-Type", "application/json") - testhelper.TestHeader(t, r, "Accept", "application/json") - testhelper.TestJSONRequest(t, r, requestJSON) + th.Mux.HandleFunc("/ec2tokens", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestJSONRequest(t, r, requestJSON) w.WriteHeader(http.StatusOK) fmt.Fprintf(w, tokens_testing.TokenOutput) @@ -40,8 +40,8 @@ func authTokenPost(t *testing.T, options ec2tokens.AuthOptions, requestJSON stri } actual, err := ec2tokens.Create(context.TODO(), &client, &options).Extract() - testhelper.AssertNoErr(t, err) - testhelper.CheckDeepEquals(t, expected, actual) + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, expected, actual) } func TestCreateV2(t *testing.T) { @@ -224,7 +224,7 @@ func TestEC2CredentialsBuildCanonicalQueryStringV2(t *testing.T) { "Value": "bar", } expected := "Action=foo&Value=bar" - testhelper.CheckEquals(t, expected, ec2tokens.EC2CredentialsBuildCanonicalQueryStringV2(params)) + th.CheckEquals(t, expected, ec2tokens.EC2CredentialsBuildCanonicalQueryStringV2(params)) } func TestEC2CredentialsBuildStringToSignV2(t *testing.T) { @@ -238,7 +238,7 @@ func TestEC2CredentialsBuildStringToSignV2(t *testing.T) { }, } expected := []byte("GET\nlocalhost\n/\nAction=foo&Value=bar") - testhelper.CheckDeepEquals(t, expected, ec2tokens.EC2CredentialsBuildStringToSignV2(opts)) + th.CheckDeepEquals(t, expected, ec2tokens.EC2CredentialsBuildStringToSignV2(opts)) } func TestEC2CredentialsBuildCanonicalQueryStringV4(t *testing.T) { @@ -247,8 +247,8 @@ func TestEC2CredentialsBuildCanonicalQueryStringV4(t *testing.T) { "Value": "bar", } expected := "Action=foo&Value=bar" - testhelper.CheckEquals(t, expected, ec2tokens.EC2CredentialsBuildCanonicalQueryStringV4("foo", params)) - testhelper.CheckEquals(t, "", ec2tokens.EC2CredentialsBuildCanonicalQueryStringV4("POST", params)) + th.CheckEquals(t, expected, ec2tokens.EC2CredentialsBuildCanonicalQueryStringV4("foo", params)) + th.CheckEquals(t, "", ec2tokens.EC2CredentialsBuildCanonicalQueryStringV4("POST", params)) } func TestEC2CredentialsBuildCanonicalHeadersV4(t *testing.T) { @@ -258,12 +258,12 @@ func TestEC2CredentialsBuildCanonicalHeadersV4(t *testing.T) { } signedHeaders := "foo;baz" expected := "foo:bar\nbaz:qux\n" - testhelper.CheckEquals(t, expected, ec2tokens.EC2CredentialsBuildCanonicalHeadersV4(headers, signedHeaders)) + th.CheckEquals(t, expected, ec2tokens.EC2CredentialsBuildCanonicalHeadersV4(headers, signedHeaders)) } func TestEC2CredentialsBuildSignatureKeyV4(t *testing.T) { expected := "246626bd815b0a0cae4bedc3f4e124ca25e208cd75fd812d836aeae184de038a" - testhelper.CheckEquals(t, expected, hex.EncodeToString((ec2tokens.EC2CredentialsBuildSignatureKeyV4("foo", "bar", "baz", time.Time{})))) + th.CheckEquals(t, expected, hex.EncodeToString((ec2tokens.EC2CredentialsBuildSignatureKeyV4("foo", "bar", "baz", time.Time{})))) } func TestEC2CredentialsBuildSignatureV4(t *testing.T) { @@ -284,5 +284,5 @@ func TestEC2CredentialsBuildSignatureV4(t *testing.T) { stringToSign := ec2tokens.EC2CredentialsBuildStringToSignV4(opts, "host", "foo", date) key := ec2tokens.EC2CredentialsBuildSignatureKeyV4("", "", "", date) - testhelper.CheckEquals(t, expected, ec2tokens.EC2CredentialsBuildSignatureV4(key, stringToSign)) + th.CheckEquals(t, expected, ec2tokens.EC2CredentialsBuildSignatureV4(key, stringToSign)) } diff --git a/openstack/identity/v3/oauth1/testing/fixtures_test.go b/openstack/identity/v3/oauth1/testing/fixtures_test.go index 8a2bfe5cdb..3e8d144047 100644 --- a/openstack/identity/v3/oauth1/testing/fixtures_test.go +++ b/openstack/identity/v3/oauth1/testing/fixtures_test.go @@ -8,7 +8,7 @@ import ( "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/oauth1" tokens "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/tokens/testing" - "github.com/gophercloud/gophercloud/v2/testhelper" + th "github.com/gophercloud/gophercloud/v2/testhelper" "github.com/gophercloud/gophercloud/v2/testhelper/client" ) @@ -221,39 +221,39 @@ var ExpectedUserAccessTokenRolesSlice = []oauth1.AccessTokenRole{UserAccessToken // HandleCreateConsumer creates an HTTP handler at `/OS-OAUTH1/consumers` on the // test handler mux that tests consumer creation. func HandleCreateConsumer(t *testing.T) { - testhelper.Mux.HandleFunc("/OS-OAUTH1/consumers", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "POST") - testhelper.TestHeader(t, r, "Content-Type", "application/json") - testhelper.TestHeader(t, r, "Accept", "application/json") - testhelper.TestJSONRequest(t, r, CreateConsumerRequest) + th.Mux.HandleFunc("/OS-OAUTH1/consumers", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestJSONRequest(t, r, CreateConsumerRequest) w.WriteHeader(http.StatusCreated) _, err := fmt.Fprintf(w, CreateConsumerResponse) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) }) } // HandleUpdateConsumer creates an HTTP handler at `/OS-OAUTH1/consumers/7fea2d` on the // test handler mux that tests consumer update. func HandleUpdateConsumer(t *testing.T) { - testhelper.Mux.HandleFunc("/OS-OAUTH1/consumers/7fea2d", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "PATCH") - testhelper.TestHeader(t, r, "Content-Type", "application/json") - testhelper.TestHeader(t, r, "Accept", "application/json") - testhelper.TestJSONRequest(t, r, UpdateConsumerRequest) + th.Mux.HandleFunc("/OS-OAUTH1/consumers/7fea2d", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "PATCH") + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestJSONRequest(t, r, UpdateConsumerRequest) w.WriteHeader(http.StatusOK) _, err := fmt.Fprintf(w, UpdateConsumerResponse) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) }) } // HandleDeleteConsumer creates an HTTP handler at `/OS-OAUTH1/consumers/7fea2d` on the // test handler mux that tests consumer deletion. func HandleDeleteConsumer(t *testing.T) { - testhelper.Mux.HandleFunc("/OS-OAUTH1/consumers/7fea2d", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "DELETE") - testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.Mux.HandleFunc("/OS-OAUTH1/consumers/7fea2d", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "DELETE") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.WriteHeader(http.StatusNoContent) }) @@ -262,10 +262,10 @@ func HandleDeleteConsumer(t *testing.T) { // HandleGetConsumer creates an HTTP handler at `/OS-OAUTH1/consumers/7fea2d` on the // test handler mux that responds with a single consumer. func HandleGetConsumer(t *testing.T) { - testhelper.Mux.HandleFunc("/OS-OAUTH1/consumers/7fea2d", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "GET") - testhelper.TestHeader(t, r, "Accept", "application/json") - testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.Mux.HandleFunc("/OS-OAUTH1/consumers/7fea2d", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "Accept", "application/json") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) @@ -299,10 +299,10 @@ var ExpectedConsumersSlice = []oauth1.Consumer{FirstConsumer, SecondConsumer} // HandleListConsumers creates an HTTP handler at `/OS-OAUTH1/consumers` on the // test handler mux that responds with a list of two consumers. func HandleListConsumers(t *testing.T) { - testhelper.Mux.HandleFunc("/OS-OAUTH1/consumers", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "GET") - testhelper.TestHeader(t, r, "Accept", "application/json") - testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.Mux.HandleFunc("/OS-OAUTH1/consumers", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "Accept", "application/json") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) @@ -319,13 +319,13 @@ var Token = oauth1.Token{ // HandleRequestToken creates an HTTP handler at `/OS-OAUTH1/request_token` on the // test handler mux that responds with a OAuth1 unauthorized token. func HandleRequestToken(t *testing.T) { - testhelper.Mux.HandleFunc("/OS-OAUTH1/request_token", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "POST") - testhelper.TestHeader(t, r, "Accept", "application/json") - testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID) - testhelper.TestHeader(t, r, "Authorization", `OAuth oauth_callback="oob", oauth_consumer_key="7fea2d", oauth_nonce="71416001758914252991586795052", oauth_signature_method="HMAC-SHA1", oauth_timestamp="0", oauth_version="1.0", oauth_signature="jCSPVryCYF52Ks0VNNmBmeKSGuw%3D"`) - testhelper.TestHeader(t, r, "Requested-Project-Id", "1df927e8a466498f98788ed73d3c8ab4") - testhelper.TestBody(t, r, "") + th.Mux.HandleFunc("/OS-OAUTH1/request_token", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "Accept", "application/json") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.TestHeader(t, r, "Authorization", `OAuth oauth_callback="oob", oauth_consumer_key="7fea2d", oauth_nonce="71416001758914252991586795052", oauth_signature_method="HMAC-SHA1", oauth_timestamp="0", oauth_version="1.0", oauth_signature="jCSPVryCYF52Ks0VNNmBmeKSGuw%3D"`) + th.TestHeader(t, r, "Requested-Project-Id", "1df927e8a466498f98788ed73d3c8ab4") + th.TestBody(t, r, "") w.Header().Set("Content-Type", oauth1.OAuth1TokenContentType) w.WriteHeader(http.StatusCreated) @@ -336,15 +336,15 @@ func HandleRequestToken(t *testing.T) { // HandleAuthorizeToken creates an HTTP handler at `/OS-OAUTH1/authorize/29971f` on the // test handler mux that tests unauthorized token authorization. func HandleAuthorizeToken(t *testing.T) { - testhelper.Mux.HandleFunc("/OS-OAUTH1/authorize/29971f", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "PUT") - testhelper.TestHeader(t, r, "Content-Type", "application/json") - testhelper.TestHeader(t, r, "Accept", "application/json") - testhelper.TestJSONRequest(t, r, AuthorizeTokenRequest) + th.Mux.HandleFunc("/OS-OAUTH1/authorize/29971f", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "PUT") + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestJSONRequest(t, r, AuthorizeTokenRequest) w.WriteHeader(http.StatusOK) _, err := fmt.Fprintf(w, AuthorizeTokenResponse) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) }) } @@ -357,12 +357,12 @@ var AccessToken = oauth1.Token{ // HandleCreateAccessToken creates an HTTP handler at `/OS-OAUTH1/access_token` on the // test handler mux that responds with a OAuth1 access token. func HandleCreateAccessToken(t *testing.T) { - testhelper.Mux.HandleFunc("/OS-OAUTH1/access_token", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "POST") - testhelper.TestHeader(t, r, "Accept", "application/json") - testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID) - testhelper.TestHeader(t, r, "Authorization", `OAuth oauth_consumer_key="7fea2d", oauth_nonce="66148873158553341551586804894", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1586804894", oauth_token="29971f", oauth_verifier="8171", oauth_version="1.0", oauth_signature="usQ89Y3IYG0IBE7%2Ft8aVsc8XgEk%3D"`) - testhelper.TestBody(t, r, "") + th.Mux.HandleFunc("/OS-OAUTH1/access_token", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "Accept", "application/json") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.TestHeader(t, r, "Authorization", `OAuth oauth_consumer_key="7fea2d", oauth_nonce="66148873158553341551586804894", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1586804894", oauth_token="29971f", oauth_verifier="8171", oauth_version="1.0", oauth_signature="usQ89Y3IYG0IBE7%2Ft8aVsc8XgEk%3D"`) + th.TestBody(t, r, "") w.Header().Set("Content-Type", oauth1.OAuth1TokenContentType) w.WriteHeader(http.StatusCreated) @@ -373,10 +373,10 @@ func HandleCreateAccessToken(t *testing.T) { // HandleGetAccessToken creates an HTTP handler at `/users/ce9e07/OS-OAUTH1/access_tokens/6be26a` on the // test handler mux that responds with a single access token. func HandleGetAccessToken(t *testing.T) { - testhelper.Mux.HandleFunc("/users/ce9e07/OS-OAUTH1/access_tokens/6be26a", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "GET") - testhelper.TestHeader(t, r, "Accept", "application/json") - testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.Mux.HandleFunc("/users/ce9e07/OS-OAUTH1/access_tokens/6be26a", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "Accept", "application/json") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) @@ -387,9 +387,9 @@ func HandleGetAccessToken(t *testing.T) { // HandleRevokeAccessToken creates an HTTP handler at `/users/ce9e07/OS-OAUTH1/access_tokens/6be26a` on the // test handler mux that tests access token deletion. func HandleRevokeAccessToken(t *testing.T) { - testhelper.Mux.HandleFunc("/users/ce9e07/OS-OAUTH1/access_tokens/6be26a", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "DELETE") - testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.Mux.HandleFunc("/users/ce9e07/OS-OAUTH1/access_tokens/6be26a", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "DELETE") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.WriteHeader(http.StatusNoContent) }) @@ -398,10 +398,10 @@ func HandleRevokeAccessToken(t *testing.T) { // HandleListAccessTokens creates an HTTP handler at `/users/ce9e07/OS-OAUTH1/access_tokens` on the // test handler mux that responds with a slice of access tokens. func HandleListAccessTokens(t *testing.T) { - testhelper.Mux.HandleFunc("/users/ce9e07/OS-OAUTH1/access_tokens", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "GET") - testhelper.TestHeader(t, r, "Accept", "application/json") - testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.Mux.HandleFunc("/users/ce9e07/OS-OAUTH1/access_tokens", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "Accept", "application/json") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) @@ -412,10 +412,10 @@ func HandleListAccessTokens(t *testing.T) { // HandleListAccessTokenRoles creates an HTTP handler at `/users/ce9e07/OS-OAUTH1/access_tokens/6be26a/roles` on the // test handler mux that responds with a slice of access token roles. func HandleListAccessTokenRoles(t *testing.T) { - testhelper.Mux.HandleFunc("/users/ce9e07/OS-OAUTH1/access_tokens/6be26a/roles", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "GET") - testhelper.TestHeader(t, r, "Accept", "application/json") - testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.Mux.HandleFunc("/users/ce9e07/OS-OAUTH1/access_tokens/6be26a/roles", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "Accept", "application/json") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) @@ -426,10 +426,10 @@ func HandleListAccessTokenRoles(t *testing.T) { // HandleGetAccessTokenRole creates an HTTP handler at `/users/ce9e07/OS-OAUTH1/access_tokens/6be26a/roles/5ad150` on the // test handler mux that responds with an access token role. func HandleGetAccessTokenRole(t *testing.T) { - testhelper.Mux.HandleFunc("/users/ce9e07/OS-OAUTH1/access_tokens/6be26a/roles/5ad150", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "GET") - testhelper.TestHeader(t, r, "Accept", "application/json") - testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.Mux.HandleFunc("/users/ce9e07/OS-OAUTH1/access_tokens/6be26a/roles/5ad150", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "Accept", "application/json") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) @@ -440,12 +440,12 @@ func HandleGetAccessTokenRole(t *testing.T) { // HandleAuthenticate creates an HTTP handler at `/auth/tokens` on the // test handler mux that responds with an OpenStack token. func HandleAuthenticate(t *testing.T) { - testhelper.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "POST") - testhelper.TestHeader(t, r, "Content-Type", "application/json") - testhelper.TestHeader(t, r, "Accept", "application/json") - testhelper.TestHeader(t, r, "Authorization", `OAuth oauth_consumer_key="7fea2d", oauth_nonce="66148873158553341551586804894", oauth_signature_method="HMAC-SHA1", oauth_timestamp="0", oauth_token="accd36", oauth_version="1.0", oauth_signature="JgMHu4e7rXGlqz3A%2FLhHDMvtjp8%3D"`) - testhelper.TestJSONRequest(t, r, `{"auth": {"identity": {"oauth1": {}, "methods": ["oauth1"]}}}`) + th.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestHeader(t, r, "Authorization", `OAuth oauth_consumer_key="7fea2d", oauth_nonce="66148873158553341551586804894", oauth_signature_method="HMAC-SHA1", oauth_timestamp="0", oauth_token="accd36", oauth_version="1.0", oauth_signature="JgMHu4e7rXGlqz3A%2FLhHDMvtjp8%3D"`) + th.TestJSONRequest(t, r, `{"auth": {"identity": {"oauth1": {}, "methods": ["oauth1"]}}}`) w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) diff --git a/openstack/identity/v3/tokens/testing/fixtures.go b/openstack/identity/v3/tokens/testing/fixtures.go index 0b4ccafa26..00797867c9 100644 --- a/openstack/identity/v3/tokens/testing/fixtures.go +++ b/openstack/identity/v3/tokens/testing/fixtures.go @@ -8,7 +8,7 @@ import ( "github.com/gophercloud/gophercloud/v2" "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/tokens" - "github.com/gophercloud/gophercloud/v2/testhelper" + th "github.com/gophercloud/gophercloud/v2/testhelper" ) const testTokenID = "130f6c17-420e-4a0b-97b0-0c9cf2a05f30" @@ -310,7 +310,7 @@ func getGetResult(t *testing.T) tokens.GetResult { "X-Subject-Token": []string{testTokenID}, } err := json.Unmarshal([]byte(TokenOutput), &result.Body) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) return result } @@ -320,6 +320,6 @@ func getGetDomainResult(t *testing.T) tokens.GetResult { "X-Subject-Token": []string{testTokenID}, } err := json.Unmarshal([]byte(DomainToken), &result.Body) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) return result } diff --git a/openstack/identity/v3/tokens/testing/requests_test.go b/openstack/identity/v3/tokens/testing/requests_test.go index 9a9a59fc14..c0aafb9ad4 100644 --- a/openstack/identity/v3/tokens/testing/requests_test.go +++ b/openstack/identity/v3/tokens/testing/requests_test.go @@ -9,25 +9,25 @@ import ( "github.com/gophercloud/gophercloud/v2" "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/tokens" - "github.com/gophercloud/gophercloud/v2/testhelper" + th "github.com/gophercloud/gophercloud/v2/testhelper" "github.com/gophercloud/gophercloud/v2/testhelper/client" ) // authTokenPost verifies that providing certain AuthOptions and Scope results in an expected JSON structure. func authTokenPost(t *testing.T, options tokens.AuthOptions, scope *tokens.Scope, requestJSON string) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() client := gophercloud.ServiceClient{ ProviderClient: &gophercloud.ProviderClient{}, - Endpoint: testhelper.Endpoint(), + Endpoint: th.Endpoint(), } - testhelper.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "POST") - testhelper.TestHeader(t, r, "Content-Type", "application/json") - testhelper.TestHeader(t, r, "Accept", "application/json") - testhelper.TestJSONRequest(t, r, requestJSON) + th.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestJSONRequest(t, r, requestJSON) w.WriteHeader(http.StatusCreated) fmt.Fprintf(w, `{ @@ -45,17 +45,17 @@ func authTokenPost(t *testing.T, options tokens.AuthOptions, scope *tokens.Scope ExpiresAt: time.Date(2014, 10, 2, 13, 45, 0, 0, time.UTC), } actual, err := tokens.Create(context.TODO(), &client, &options).Extract() - testhelper.AssertNoErr(t, err) - testhelper.CheckDeepEquals(t, expected, actual) + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, expected, actual) } func authTokenPostErr(t *testing.T, options tokens.AuthOptions, scope *tokens.Scope, includeToken bool, expectedErr error) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() client := gophercloud.ServiceClient{ ProviderClient: &gophercloud.ProviderClient{}, - Endpoint: testhelper.Endpoint(), + Endpoint: th.Endpoint(), } if includeToken { client.TokenID = "abcdef123456" @@ -303,8 +303,8 @@ func TestCreateSystemScope(t *testing.T) { } func TestCreateUserIDPasswordTrustID(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() requestJSON := `{ "auth": { @@ -362,11 +362,11 @@ func TestCreateUserIDPasswordTrustID(t *testing.T) { } } }` - testhelper.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "POST") - testhelper.TestHeader(t, r, "Content-Type", "application/json") - testhelper.TestHeader(t, r, "Accept", "application/json") - testhelper.TestJSONRequest(t, r, requestJSON) + th.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestJSONRequest(t, r, requestJSON) w.WriteHeader(http.StatusCreated) fmt.Fprintf(w, responseJSON) @@ -389,7 +389,7 @@ func TestCreateUserIDPasswordTrustID(t *testing.T) { expectedToken := &tokens.Token{ ExpiresAt: time.Date(2024, 02, 28, 12, 10, 39, 0, time.UTC), } - testhelper.AssertDeepEquals(t, expectedToken, token) + th.AssertDeepEquals(t, expectedToken, token) trust, err := rsp.ExtractTrust() if err != nil { @@ -405,7 +405,7 @@ func TestCreateUserIDPasswordTrustID(t *testing.T) { ID: "c88693b7c81c408e9084ac1e51082bfb", }, } - testhelper.AssertDeepEquals(t, expectedTrust, trust) + th.AssertDeepEquals(t, expectedTrust, trust) } func TestCreateApplicationCredentialIDAndSecret(t *testing.T) { @@ -513,15 +513,15 @@ func TestCreatePasswordTOTPProjectNameAndDomainNameScope(t *testing.T) { } func TestCreateExtractsTokenFromResponse(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() client := gophercloud.ServiceClient{ ProviderClient: &gophercloud.ProviderClient{}, - Endpoint: testhelper.Endpoint(), + Endpoint: th.Endpoint(), } - testhelper.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) { + th.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) { w.Header().Add("X-Subject-Token", "aaa111") w.WriteHeader(http.StatusCreated) @@ -652,22 +652,22 @@ func TestCreateFailureEmptyScope(t *testing.T) { */ func TestGetRequest(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() client := gophercloud.ServiceClient{ ProviderClient: &gophercloud.ProviderClient{ TokenID: "12345abcdef", }, - Endpoint: testhelper.Endpoint(), + Endpoint: th.Endpoint(), } - testhelper.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "GET") - testhelper.TestHeaderUnset(t, r, "Content-Type") - testhelper.TestHeader(t, r, "Accept", "application/json") - testhelper.TestHeader(t, r, "X-Auth-Token", "12345abcdef") - testhelper.TestHeader(t, r, "X-Subject-Token", "abcdef12345") + th.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeaderUnset(t, r, "Content-Type") + th.TestHeader(t, r, "Accept", "application/json") + th.TestHeader(t, r, "X-Auth-Token", "12345abcdef") + th.TestHeader(t, r, "X-Subject-Token", "abcdef12345") w.WriteHeader(http.StatusOK) fmt.Fprintf(w, ` @@ -691,15 +691,15 @@ func prepareAuthTokenHandler(t *testing.T, expectedMethod string, status int) go ProviderClient: &gophercloud.ProviderClient{ TokenID: "12345abcdef", }, - Endpoint: testhelper.Endpoint(), + Endpoint: th.Endpoint(), } - testhelper.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, expectedMethod) - testhelper.TestHeaderUnset(t, r, "Content-Type") - testhelper.TestHeader(t, r, "Accept", "application/json") - testhelper.TestHeader(t, r, "X-Auth-Token", "12345abcdef") - testhelper.TestHeader(t, r, "X-Subject-Token", "abcdef12345") + th.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, expectedMethod) + th.TestHeaderUnset(t, r, "Content-Type") + th.TestHeader(t, r, "Accept", "application/json") + th.TestHeader(t, r, "X-Auth-Token", "12345abcdef") + th.TestHeader(t, r, "X-Subject-Token", "abcdef12345") w.WriteHeader(status) }) @@ -708,8 +708,8 @@ func prepareAuthTokenHandler(t *testing.T, expectedMethod string, status int) go } func TestValidateRequestSuccessful(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() client := prepareAuthTokenHandler(t, "HEAD", http.StatusNoContent) ok, err := tokens.Validate(context.TODO(), &client, "abcdef12345") @@ -723,8 +723,8 @@ func TestValidateRequestSuccessful(t *testing.T) { } func TestValidateRequestFailure(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() client := prepareAuthTokenHandler(t, "HEAD", http.StatusNotFound) ok, err := tokens.Validate(context.TODO(), &client, "abcdef12345") @@ -738,8 +738,8 @@ func TestValidateRequestFailure(t *testing.T) { } func TestValidateRequestError(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() client := prepareAuthTokenHandler(t, "HEAD", http.StatusMethodNotAllowed) _, err := tokens.Validate(context.TODO(), &client, "abcdef12345") @@ -749,17 +749,17 @@ func TestValidateRequestError(t *testing.T) { } func TestRevokeRequestSuccessful(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() client := prepareAuthTokenHandler(t, "DELETE", http.StatusNoContent) res := tokens.Revoke(context.TODO(), &client, "abcdef12345") - testhelper.AssertNoErr(t, res.Err) + th.AssertNoErr(t, res.Err) } func TestRevokeRequestError(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() client := prepareAuthTokenHandler(t, "DELETE", http.StatusNotFound) res := tokens.Revoke(context.TODO(), &client, "abcdef12345") @@ -769,20 +769,20 @@ func TestRevokeRequestError(t *testing.T) { } func TestNoTokenInResponse(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() client := gophercloud.ServiceClient{ ProviderClient: &gophercloud.ProviderClient{}, - Endpoint: testhelper.Endpoint(), + Endpoint: th.Endpoint(), } - testhelper.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) { + th.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusCreated) fmt.Fprintf(w, `{}`) }) options := tokens.AuthOptions{UserID: "me", Password: "squirrel!"} _, err := tokens.Create(context.TODO(), &client, &options).Extract() - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) } diff --git a/openstack/identity/v3/tokens/testing/results_test.go b/openstack/identity/v3/tokens/testing/results_test.go index e142ac9c57..c45581ffde 100644 --- a/openstack/identity/v3/tokens/testing/results_test.go +++ b/openstack/identity/v3/tokens/testing/results_test.go @@ -3,59 +3,59 @@ package testing import ( "testing" - "github.com/gophercloud/gophercloud/v2/testhelper" + th "github.com/gophercloud/gophercloud/v2/testhelper" ) func TestExtractToken(t *testing.T) { result := getGetResult(t) token, err := result.ExtractToken() - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) - testhelper.CheckDeepEquals(t, &ExpectedToken, token) + th.CheckDeepEquals(t, &ExpectedToken, token) } func TestExtractCatalog(t *testing.T) { result := getGetResult(t) catalog, err := result.ExtractServiceCatalog() - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) - testhelper.CheckDeepEquals(t, &ExpectedServiceCatalog, catalog) + th.CheckDeepEquals(t, &ExpectedServiceCatalog, catalog) } func TestExtractUser(t *testing.T) { result := getGetResult(t) user, err := result.ExtractUser() - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) - testhelper.CheckDeepEquals(t, &ExpectedUser, user) + th.CheckDeepEquals(t, &ExpectedUser, user) } func TestExtractRoles(t *testing.T) { result := getGetResult(t) roles, err := result.ExtractRoles() - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) - testhelper.CheckDeepEquals(t, ExpectedRoles, roles) + th.CheckDeepEquals(t, ExpectedRoles, roles) } func TestExtractProject(t *testing.T) { result := getGetResult(t) project, err := result.ExtractProject() - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) - testhelper.CheckDeepEquals(t, &ExpectedProject, project) + th.CheckDeepEquals(t, &ExpectedProject, project) } func TestExtractDomain(t *testing.T) { result := getGetDomainResult(t) domain, err := result.ExtractDomain() - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) - testhelper.CheckDeepEquals(t, &ExpectedDomain, domain) + th.CheckDeepEquals(t, &ExpectedDomain, domain) } diff --git a/openstack/identity/v3/trusts/testing/fixtures_test.go b/openstack/identity/v3/trusts/testing/fixtures_test.go index 19ede76569..6cc9a8a7d1 100644 --- a/openstack/identity/v3/trusts/testing/fixtures_test.go +++ b/openstack/identity/v3/trusts/testing/fixtures_test.go @@ -7,7 +7,7 @@ import ( "time" "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/trusts" - "github.com/gophercloud/gophercloud/v2/testhelper" + th "github.com/gophercloud/gophercloud/v2/testhelper" "github.com/gophercloud/gophercloud/v2/testhelper/client" ) @@ -201,37 +201,37 @@ var ExpectedTrustRolesSlice = []trusts.Role{FirstRole, SecondRole} // HandleCreateTrust creates an HTTP handler at `/OS-TRUST/trusts` on the // test handler mux that tests trust creation. func HandleCreateTrust(t *testing.T) { - testhelper.Mux.HandleFunc("/OS-TRUST/trusts", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "POST") - testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID) - testhelper.TestJSONRequest(t, r, CreateRequest) + th.Mux.HandleFunc("/OS-TRUST/trusts", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.TestJSONRequest(t, r, CreateRequest) w.WriteHeader(http.StatusCreated) _, err := fmt.Fprintf(w, CreateResponse) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) }) } // HandleCreateTrustNoExpire creates an HTTP handler at `/OS-TRUST/trusts` on the // test handler mux that tests trust creation. func HandleCreateTrustNoExpire(t *testing.T) { - testhelper.Mux.HandleFunc("/OS-TRUST/trusts", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "POST") - testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID) - testhelper.TestJSONRequest(t, r, CreateRequestNoExpire) + th.Mux.HandleFunc("/OS-TRUST/trusts", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.TestJSONRequest(t, r, CreateRequestNoExpire) w.WriteHeader(http.StatusCreated) _, err := fmt.Fprintf(w, CreateResponseNoExpire) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) }) } // HandleDeleteUserSuccessfully creates an HTTP handler at `/users` on the // test handler mux that tests user deletion. func HandleDeleteTrust(t *testing.T) { - testhelper.Mux.HandleFunc("/OS-TRUST/trusts/3422b7c113894f5d90665e1a79655e23", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "DELETE") - testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.Mux.HandleFunc("/OS-TRUST/trusts/3422b7c113894f5d90665e1a79655e23", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "DELETE") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.WriteHeader(http.StatusNoContent) }) @@ -240,10 +240,10 @@ func HandleDeleteTrust(t *testing.T) { // HandleGetTrustSuccessfully creates an HTTP handler at `/OS-TRUST/trusts` on the // test handler mux that responds with a single trusts. func HandleGetTrustSuccessfully(t *testing.T) { - testhelper.Mux.HandleFunc("/OS-TRUST/trusts/987fe8", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "GET") - testhelper.TestHeader(t, r, "Accept", "application/json") - testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.Mux.HandleFunc("/OS-TRUST/trusts/987fe8", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "Accept", "application/json") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) @@ -310,10 +310,10 @@ var ExpectedTrustsSlice = []trusts.Trust{FirstTrust, SecondTrust} // HandleListTrustsSuccessfully creates an HTTP handler at `/OS-TRUST/trusts` on the // test handler mux that responds with a list of two trusts. func HandleListTrustsSuccessfully(t *testing.T) { - testhelper.Mux.HandleFunc("/OS-TRUST/trusts", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "GET") - testhelper.TestHeader(t, r, "Accept", "application/json") - testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.Mux.HandleFunc("/OS-TRUST/trusts", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "Accept", "application/json") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) @@ -324,10 +324,10 @@ func HandleListTrustsSuccessfully(t *testing.T) { // HandleListTrustRolesSuccessfully creates an HTTP handler at `/OS-TRUST/trusts/987fe8/roles` on the // test handler mux that responds with a list trust roles. func HandleListTrustRolesSuccessfully(t *testing.T) { - testhelper.Mux.HandleFunc("/OS-TRUST/trusts/987fe8/roles", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "GET") - testhelper.TestHeader(t, r, "Accept", "application/json") - testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.Mux.HandleFunc("/OS-TRUST/trusts/987fe8/roles", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "Accept", "application/json") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) @@ -338,10 +338,10 @@ func HandleListTrustRolesSuccessfully(t *testing.T) { // HandleGetTrustRoleSuccessfully creates an HTTP handler at `/OS-TRUST/trusts/987fe8/roles/c1648e` on the // test handler mux that responds with a trust role details. func HandleGetTrustRoleSuccessfully(t *testing.T) { - testhelper.Mux.HandleFunc("/OS-TRUST/trusts/987fe8/roles/c1648e", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "GET") - testhelper.TestHeader(t, r, "Accept", "application/json") - testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.Mux.HandleFunc("/OS-TRUST/trusts/987fe8/roles/c1648e", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "Accept", "application/json") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) @@ -352,10 +352,10 @@ func HandleGetTrustRoleSuccessfully(t *testing.T) { // HandleCheckTrustRoleSuccessfully creates an HTTP handler at `/OS-TRUST/trusts/987fe8/roles/c1648e` on the // test handler mux that responds with a list trust roles. func HandleCheckTrustRoleSuccessfully(t *testing.T) { - testhelper.Mux.HandleFunc("/OS-TRUST/trusts/987fe8/roles/c1648e", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "HEAD") - testhelper.TestHeader(t, r, "Accept", "application/json") - testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.Mux.HandleFunc("/OS-TRUST/trusts/987fe8/roles/c1648e", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "HEAD") + th.TestHeader(t, r, "Accept", "application/json") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.WriteHeader(http.StatusOK) }) diff --git a/openstack/sharedfilesystems/v2/schedulerstats/testing/fixtures_test.go b/openstack/sharedfilesystems/v2/schedulerstats/testing/fixtures_test.go index acdd04d53f..88c4b31203 100644 --- a/openstack/sharedfilesystems/v2/schedulerstats/testing/fixtures_test.go +++ b/openstack/sharedfilesystems/v2/schedulerstats/testing/fixtures_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/gophercloud/gophercloud/v2/openstack/sharedfilesystems/v2/schedulerstats" - "github.com/gophercloud/gophercloud/v2/testhelper" + th "github.com/gophercloud/gophercloud/v2/testhelper" "github.com/gophercloud/gophercloud/v2/testhelper/client" ) @@ -265,9 +265,9 @@ var ( ) func HandlePoolsListSuccessfully(t *testing.T) { - testhelper.Mux.HandleFunc("/scheduler-stats/pools", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "GET") - testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.Mux.HandleFunc("/scheduler-stats/pools", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") @@ -277,9 +277,9 @@ func HandlePoolsListSuccessfully(t *testing.T) { fmt.Fprintf(w, PoolsListBody) }) - testhelper.Mux.HandleFunc("/scheduler-stats/pools/detail", func(w http.ResponseWriter, r *http.Request) { - testhelper.TestMethod(t, r, "GET") - testhelper.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.Mux.HandleFunc("/scheduler-stats/pools/detail", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") diff --git a/openstack/sharedfilesystems/v2/schedulerstats/testing/requests_test.go b/openstack/sharedfilesystems/v2/schedulerstats/testing/requests_test.go index 5c2ff36ad9..d6b826ed74 100644 --- a/openstack/sharedfilesystems/v2/schedulerstats/testing/requests_test.go +++ b/openstack/sharedfilesystems/v2/schedulerstats/testing/requests_test.go @@ -6,13 +6,13 @@ import ( "github.com/gophercloud/gophercloud/v2/openstack/sharedfilesystems/v2/schedulerstats" "github.com/gophercloud/gophercloud/v2/pagination" - "github.com/gophercloud/gophercloud/v2/testhelper" + th "github.com/gophercloud/gophercloud/v2/testhelper" "github.com/gophercloud/gophercloud/v2/testhelper/client" ) func TestListPoolsDetail(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() HandlePoolsListSuccessfully(t) pages := 0 @@ -20,20 +20,20 @@ func TestListPoolsDetail(t *testing.T) { pages++ actual, err := schedulerstats.ExtractPools(page) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) if len(actual) != 4 { t.Fatalf("Expected 4 backends, got %d", len(actual)) } - testhelper.CheckDeepEquals(t, PoolFake1, actual[0]) - testhelper.CheckDeepEquals(t, PoolFake2, actual[1]) - testhelper.CheckDeepEquals(t, PoolFake3, actual[2]) - testhelper.CheckDeepEquals(t, PoolFake4, actual[3]) + th.CheckDeepEquals(t, PoolFake1, actual[0]) + th.CheckDeepEquals(t, PoolFake2, actual[1]) + th.CheckDeepEquals(t, PoolFake3, actual[2]) + th.CheckDeepEquals(t, PoolFake4, actual[3]) return true, nil }) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) if pages != 1 { t.Errorf("Expected 1 page, saw %d", pages) @@ -44,20 +44,20 @@ func TestListPoolsDetail(t *testing.T) { pages++ actual, err := schedulerstats.ExtractPools(page) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) if len(actual) != 4 { t.Fatalf("Expected 4 backends, got %d", len(actual)) } - testhelper.CheckDeepEquals(t, PoolDetailFake1, actual[0]) - testhelper.CheckDeepEquals(t, PoolDetailFake2, actual[1]) - testhelper.CheckDeepEquals(t, PoolDetailFake3, actual[2]) - testhelper.CheckDeepEquals(t, PoolDetailFake4, actual[3]) + th.CheckDeepEquals(t, PoolDetailFake1, actual[0]) + th.CheckDeepEquals(t, PoolDetailFake2, actual[1]) + th.CheckDeepEquals(t, PoolDetailFake3, actual[2]) + th.CheckDeepEquals(t, PoolDetailFake4, actual[3]) return true, nil }) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) if pages != 1 { t.Errorf("Expected 1 page, saw %d", pages) diff --git a/openstack/sharedfilesystems/v2/services/testing/requests_test.go b/openstack/sharedfilesystems/v2/services/testing/requests_test.go index 16607415b6..d4845ca09e 100644 --- a/openstack/sharedfilesystems/v2/services/testing/requests_test.go +++ b/openstack/sharedfilesystems/v2/services/testing/requests_test.go @@ -6,13 +6,13 @@ import ( "github.com/gophercloud/gophercloud/v2/openstack/sharedfilesystems/v2/services" "github.com/gophercloud/gophercloud/v2/pagination" - "github.com/gophercloud/gophercloud/v2/testhelper" + th "github.com/gophercloud/gophercloud/v2/testhelper" "github.com/gophercloud/gophercloud/v2/testhelper/client" ) func TestListServices(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() HandleListSuccessfully(t) pages := 0 @@ -27,13 +27,13 @@ func TestListServices(t *testing.T) { if len(actual) != 2 { t.Fatalf("Expected 2 services, got %d", len(actual)) } - testhelper.CheckDeepEquals(t, FirstFakeService, actual[0]) - testhelper.CheckDeepEquals(t, SecondFakeService, actual[1]) + th.CheckDeepEquals(t, FirstFakeService, actual[0]) + th.CheckDeepEquals(t, SecondFakeService, actual[1]) return true, nil }) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) if pages != 1 { t.Errorf("Expected 1 page, saw %d", pages) diff --git a/openstack/utils/testing/choose_version_test.go b/openstack/utils/testing/choose_version_test.go index 36d8ac37ec..c237e4e036 100644 --- a/openstack/utils/testing/choose_version_test.go +++ b/openstack/utils/testing/choose_version_test.go @@ -9,11 +9,11 @@ import ( "github.com/gophercloud/gophercloud/v2" "github.com/gophercloud/gophercloud/v2/openstack/utils" - "github.com/gophercloud/gophercloud/v2/testhelper" + th "github.com/gophercloud/gophercloud/v2/testhelper" ) func setupVersionHandler() { - testhelper.Mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + th.Mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, ` { "versions": { @@ -35,10 +35,10 @@ func setupVersionHandler() { ] } } - `, testhelper.Server.URL, testhelper.Server.URL) + `, th.Server.URL, th.Server.URL) }) // Compute v2.1 API - testhelper.Mux.HandleFunc("/compute/v2.1/", func(w http.ResponseWriter, r *http.Request) { + th.Mux.HandleFunc("/compute/v2.1/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, ` { "version": { @@ -66,10 +66,10 @@ func setupVersionHandler() { ] } } - `, testhelper.Server.URL) + `, th.Server.URL) }) // Compute v2 API - testhelper.Mux.HandleFunc("/compute/v2/", func(w http.ResponseWriter, r *http.Request) { + th.Mux.HandleFunc("/compute/v2/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, ` { "version": { @@ -97,10 +97,10 @@ func setupVersionHandler() { ] } } - `, testhelper.Server.URL) + `, th.Server.URL) }) // Ironic API - testhelper.Mux.HandleFunc("/ironic/v1/", func(w http.ResponseWriter, r *http.Request) { + th.Mux.HandleFunc("/ironic/v1/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, ` { "name": "OpenStack Ironic API", @@ -132,10 +132,10 @@ func setupVersionHandler() { } ] } - `, testhelper.Server.URL, testhelper.Server.URL) + `, th.Server.URL, th.Server.URL) }) // Ironic multi-version - testhelper.Mux.HandleFunc("/ironic/v1.2/", func(w http.ResponseWriter, r *http.Request) { + th.Mux.HandleFunc("/ironic/v1.2/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, ` { "name": "OpenStack Ironic API", @@ -179,20 +179,20 @@ func setupVersionHandler() { } ] } - `, testhelper.Server.URL, testhelper.Server.URL, testhelper.Server.URL) + `, th.Server.URL, th.Server.URL, th.Server.URL) }) } func TestChooseVersion(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() setupVersionHandler() v2 := &utils.Version{ID: "v2.0", Priority: 2, Suffix: "blarg"} v3 := &utils.Version{ID: "v3.0", Priority: 3, Suffix: "hargl"} c := &gophercloud.ProviderClient{ - IdentityBase: testhelper.Endpoint(), + IdentityBase: th.Endpoint(), IdentityEndpoint: "", } v, endpoint, err := utils.ChooseVersion(context.TODO(), c, []*utils.Version{v2, v3}) @@ -205,23 +205,23 @@ func TestChooseVersion(t *testing.T) { t.Errorf("Expected %#v to win, but %#v did instead", v3, v) } - expected := testhelper.Endpoint() + "v3.0/" + expected := th.Endpoint() + "v3.0/" if endpoint != expected { t.Errorf("Expected endpoint [%s], but was [%s] instead", expected, endpoint) } } func TestChooseVersionOpinionatedLink(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() setupVersionHandler() v2 := &utils.Version{ID: "v2.0", Priority: 2, Suffix: "nope"} v3 := &utils.Version{ID: "v3.0", Priority: 3, Suffix: "northis"} c := &gophercloud.ProviderClient{ - IdentityBase: testhelper.Endpoint(), - IdentityEndpoint: testhelper.Endpoint() + "v2.0/", + IdentityBase: th.Endpoint(), + IdentityEndpoint: th.Endpoint() + "v2.0/", } v, endpoint, err := utils.ChooseVersion(context.TODO(), c, []*utils.Version{v2, v3}) if err != nil { @@ -232,22 +232,22 @@ func TestChooseVersionOpinionatedLink(t *testing.T) { t.Errorf("Expected %#v to win, but %#v did instead", v2, v) } - expected := testhelper.Endpoint() + "v2.0/" + expected := th.Endpoint() + "v2.0/" if endpoint != expected { t.Errorf("Expected endpoint [%s], but was [%s] instead", expected, endpoint) } } func TestChooseVersionFromSuffix(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() v2 := &utils.Version{ID: "v2.0", Priority: 2, Suffix: "/v2.0/"} v3 := &utils.Version{ID: "v3.0", Priority: 3, Suffix: "/v3.0/"} c := &gophercloud.ProviderClient{ - IdentityBase: testhelper.Endpoint(), - IdentityEndpoint: testhelper.Endpoint() + "v2.0/", + IdentityBase: th.Endpoint(), + IdentityEndpoint: th.Endpoint() + "v2.0/", } v, endpoint, err := utils.ChooseVersion(context.TODO(), c, []*utils.Version{v2, v3}) if err != nil { @@ -258,7 +258,7 @@ func TestChooseVersionFromSuffix(t *testing.T) { t.Errorf("Expected %#v to win, but %#v did instead", v2, v) } - expected := testhelper.Endpoint() + "v2.0/" + expected := th.Endpoint() + "v2.0/" if endpoint != expected { t.Errorf("Expected endpoint [%s], but was [%s] instead", expected, endpoint) } @@ -272,33 +272,33 @@ type getSupportedServiceMicroversions struct { } func TestGetSupportedVersions(t *testing.T) { - testhelper.SetupHTTP() - defer testhelper.TeardownHTTP() + th.SetupHTTP() + defer th.TeardownHTTP() setupVersionHandler() tests := []getSupportedServiceMicroversions{ { // v2 does not support microversions and returns error - Endpoint: testhelper.Endpoint() + "compute/v2/", + Endpoint: th.Endpoint() + "compute/v2/", ExpectedMax: "", ExpectedMin: "", ExpectedErr: true, }, { - Endpoint: testhelper.Endpoint() + "compute/v2.1/", + Endpoint: th.Endpoint() + "compute/v2.1/", ExpectedMax: "2.90", ExpectedMin: "2.1", ExpectedErr: false, }, { - Endpoint: testhelper.Endpoint() + "ironic/v1/", + Endpoint: th.Endpoint() + "ironic/v1/", ExpectedMax: "1.87", ExpectedMin: "1.1", ExpectedErr: false, }, { // This endpoint returns multiple versions, which is not supported - Endpoint: testhelper.Endpoint() + "ironic/v1.2/", + Endpoint: th.Endpoint() + "ironic/v1.2/", ExpectedMax: "not-relevant", ExpectedMin: "not-relevant", ExpectedErr: true, @@ -307,8 +307,8 @@ func TestGetSupportedVersions(t *testing.T) { for _, test := range tests { c := &gophercloud.ProviderClient{ - IdentityBase: testhelper.Endpoint(), - IdentityEndpoint: testhelper.Endpoint() + "v2.0/", + IdentityBase: th.Endpoint(), + IdentityEndpoint: th.Endpoint() + "v2.0/", } client := &gophercloud.ServiceClient{ diff --git a/pagination/testing/linked_test.go b/pagination/testing/linked_test.go index 83673f19b8..25166ad861 100644 --- a/pagination/testing/linked_test.go +++ b/pagination/testing/linked_test.go @@ -8,7 +8,7 @@ import ( "testing" "github.com/gophercloud/gophercloud/v2/pagination" - "github.com/gophercloud/gophercloud/v2/testhelper" + th "github.com/gophercloud/gophercloud/v2/testhelper" ) // LinkedPager sample and test cases. @@ -31,19 +31,19 @@ func ExtractLinkedInts(r pagination.Page) ([]int, error) { } func createLinked() pagination.Pager { - testhelper.SetupHTTP() + th.SetupHTTP() - testhelper.Mux.HandleFunc("/page1", func(w http.ResponseWriter, r *http.Request) { + th.Mux.HandleFunc("/page1", func(w http.ResponseWriter, r *http.Request) { w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, `{ "ints": [1, 2, 3], "links": { "next": "%s/page2" } }`, testhelper.Server.URL) + fmt.Fprintf(w, `{ "ints": [1, 2, 3], "links": { "next": "%s/page2" } }`, th.Server.URL) }) - testhelper.Mux.HandleFunc("/page2", func(w http.ResponseWriter, r *http.Request) { + th.Mux.HandleFunc("/page2", func(w http.ResponseWriter, r *http.Request) { w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, `{ "ints": [4, 5, 6], "links": { "next": "%s/page3" } }`, testhelper.Server.URL) + fmt.Fprintf(w, `{ "ints": [4, 5, 6], "links": { "next": "%s/page3" } }`, th.Server.URL) }) - testhelper.Mux.HandleFunc("/page3", func(w http.ResponseWriter, r *http.Request) { + th.Mux.HandleFunc("/page3", func(w http.ResponseWriter, r *http.Request) { w.Header().Add("Content-Type", "application/json") fmt.Fprintf(w, `{ "ints": [7, 8, 9], "links": { "next": null } }`) }) @@ -54,12 +54,12 @@ func createLinked() pagination.Pager { return LinkedPageResult{pagination.LinkedPageBase{PageResult: r}} } - return pagination.NewPager(client, testhelper.Server.URL+"/page1", createPage) + return pagination.NewPager(client, th.Server.URL+"/page1", createPage) } func TestEnumerateLinked(t *testing.T) { pager := createLinked() - defer testhelper.TeardownHTTP() + defer th.TeardownHTTP() callCount := 0 err := pager.EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) { @@ -101,13 +101,13 @@ func TestEnumerateLinked(t *testing.T) { func TestAllPagesLinked(t *testing.T) { pager := createLinked() - defer testhelper.TeardownHTTP() + defer th.TeardownHTTP() page, err := pager.AllPages(context.TODO()) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) expected := []int{1, 2, 3, 4, 5, 6, 7, 8, 9} actual, err := ExtractLinkedInts(page) - testhelper.AssertNoErr(t, err) - testhelper.CheckDeepEquals(t, expected, actual) + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, expected, actual) } diff --git a/pagination/testing/marker_test.go b/pagination/testing/marker_test.go index a1084ac12f..45c943e5b7 100644 --- a/pagination/testing/marker_test.go +++ b/pagination/testing/marker_test.go @@ -8,7 +8,7 @@ import ( "testing" "github.com/gophercloud/gophercloud/v2/pagination" - "github.com/gophercloud/gophercloud/v2/testhelper" + th "github.com/gophercloud/gophercloud/v2/testhelper" ) // MarkerPager sample and test cases. @@ -37,9 +37,9 @@ func (r MarkerPageResult) LastMarker() (string, error) { } func createMarkerPaged(t *testing.T) pagination.Pager { - testhelper.SetupHTTP() + th.SetupHTTP() - testhelper.Mux.HandleFunc("/page", func(w http.ResponseWriter, r *http.Request) { + th.Mux.HandleFunc("/page", func(w http.ResponseWriter, r *http.Request) { if err := r.ParseForm(); err != nil { t.Errorf("Failed to parse request form %v", err) } @@ -66,7 +66,7 @@ func createMarkerPaged(t *testing.T) pagination.Pager { return p } - return pagination.NewPager(client, testhelper.Server.URL+"/page", createPage) + return pagination.NewPager(client, th.Server.URL+"/page", createPage) } func ExtractMarkerStrings(page pagination.Page) ([]string, error) { @@ -83,7 +83,7 @@ func ExtractMarkerStrings(page pagination.Page) ([]string, error) { func TestEnumerateMarker(t *testing.T) { pager := createMarkerPaged(t) - defer testhelper.TeardownHTTP() + defer th.TeardownHTTP() callCount := 0 err := pager.EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) { @@ -107,24 +107,24 @@ func TestEnumerateMarker(t *testing.T) { return false, nil } - testhelper.CheckDeepEquals(t, expected, actual) + th.CheckDeepEquals(t, expected, actual) callCount++ return true, nil }) - testhelper.AssertNoErr(t, err) - testhelper.AssertEquals(t, callCount, 3) + th.AssertNoErr(t, err) + th.AssertEquals(t, callCount, 3) } func TestAllPagesMarker(t *testing.T) { pager := createMarkerPaged(t) - defer testhelper.TeardownHTTP() + defer th.TeardownHTTP() page, err := pager.AllPages(context.TODO()) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) expected := []string{"aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii"} actual, err := ExtractMarkerStrings(page) - testhelper.AssertNoErr(t, err) - testhelper.CheckDeepEquals(t, expected, actual) + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, expected, actual) } diff --git a/pagination/testing/pagination_test.go b/pagination/testing/pagination_test.go index b730676d4e..e10ef56847 100644 --- a/pagination/testing/pagination_test.go +++ b/pagination/testing/pagination_test.go @@ -2,12 +2,12 @@ package testing import ( "github.com/gophercloud/gophercloud/v2" - "github.com/gophercloud/gophercloud/v2/testhelper" + th "github.com/gophercloud/gophercloud/v2/testhelper" ) func createClient() *gophercloud.ServiceClient { return &gophercloud.ServiceClient{ ProviderClient: &gophercloud.ProviderClient{TokenID: "abc123"}, - Endpoint: testhelper.Endpoint(), + Endpoint: th.Endpoint(), } } diff --git a/pagination/testing/single_test.go b/pagination/testing/single_test.go index 21daedff0a..6bcd930cb2 100644 --- a/pagination/testing/single_test.go +++ b/pagination/testing/single_test.go @@ -7,7 +7,7 @@ import ( "testing" "github.com/gophercloud/gophercloud/v2/pagination" - "github.com/gophercloud/gophercloud/v2/testhelper" + th "github.com/gophercloud/gophercloud/v2/testhelper" ) // SinglePage sample and test cases. @@ -33,10 +33,10 @@ func ExtractSingleInts(r pagination.Page) ([]int, error) { } func setupSinglePaged() pagination.Pager { - testhelper.SetupHTTP() + th.SetupHTTP() client := createClient() - testhelper.Mux.HandleFunc("/only", func(w http.ResponseWriter, r *http.Request) { + th.Mux.HandleFunc("/only", func(w http.ResponseWriter, r *http.Request) { w.Header().Add("Content-Type", "application/json") fmt.Fprintf(w, `{ "ints": [1, 2, 3] }`) }) @@ -45,36 +45,36 @@ func setupSinglePaged() pagination.Pager { return SinglePageResult{pagination.SinglePageBase(r)} } - return pagination.NewPager(client, testhelper.Server.URL+"/only", createPage) + return pagination.NewPager(client, th.Server.URL+"/only", createPage) } func TestEnumerateSinglePaged(t *testing.T) { callCount := 0 pager := setupSinglePaged() - defer testhelper.TeardownHTTP() + defer th.TeardownHTTP() err := pager.EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) { callCount++ expected := []int{1, 2, 3} actual, err := ExtractSingleInts(page) - testhelper.AssertNoErr(t, err) - testhelper.CheckDeepEquals(t, expected, actual) + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, expected, actual) return true, nil }) - testhelper.CheckNoErr(t, err) - testhelper.CheckEquals(t, 1, callCount) + th.CheckNoErr(t, err) + th.CheckEquals(t, 1, callCount) } func TestAllPagesSingle(t *testing.T) { pager := setupSinglePaged() - defer testhelper.TeardownHTTP() + defer th.TeardownHTTP() page, err := pager.AllPages(context.TODO()) - testhelper.AssertNoErr(t, err) + th.AssertNoErr(t, err) expected := []int{1, 2, 3} actual, err := ExtractSingleInts(page) - testhelper.AssertNoErr(t, err) - testhelper.CheckDeepEquals(t, expected, actual) + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, expected, actual) } diff --git a/testhelper/client/fake.go b/testhelper/client/fake.go index 6e25f759d7..29514b0a65 100644 --- a/testhelper/client/fake.go +++ b/testhelper/client/fake.go @@ -2,7 +2,7 @@ package client import ( "github.com/gophercloud/gophercloud/v2" - "github.com/gophercloud/gophercloud/v2/testhelper" + th "github.com/gophercloud/gophercloud/v2/testhelper" ) // Fake token to use. @@ -12,6 +12,6 @@ const TokenID = "cbc36478b0bd8e67e89469c7749d4127" func ServiceClient() *gophercloud.ServiceClient { return &gophercloud.ServiceClient{ ProviderClient: &gophercloud.ProviderClient{TokenID: TokenID}, - Endpoint: testhelper.Endpoint(), + Endpoint: th.Endpoint(), } } From eb1fa6273c5d105d931ef850c68e8f3389d808f8 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 30 May 2024 23:54:21 +0100 Subject: [PATCH 061/429] tests: Add AssertTypeOf helper Better errors messages since we see the different types. Signed-off-by: Stephen Finucane --- testhelper/convenience.go | 10 ++++++++++ testing/auth_options_test.go | 3 +-- testing/params_test.go | 3 +-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/testhelper/convenience.go b/testhelper/convenience.go index 3b3e63979d..1ea727045f 100644 --- a/testhelper/convenience.go +++ b/testhelper/convenience.go @@ -232,6 +232,16 @@ func CheckEquals(t *testing.T, expected, actual any) { } } +// AssertDeepEquals - like Equals - performs a comparison - but on more complex +// structures that requires deeper inspection +func AssertTypeEquals(t *testing.T, expected, actual any) { + t.Helper() + + if reflect.TypeOf(expected) != reflect.TypeOf(actual) { + logFatal(t, fmt.Sprintf("expected %s but got %s", green(expected), yellow(actual))) + } +} + // AssertDeepEquals - like Equals - performs a comparison - but on more complex // structures that requires deeper inspection func AssertDeepEquals(t *testing.T, expected, actual any) { diff --git a/testing/auth_options_test.go b/testing/auth_options_test.go index 1f9b230b50..fc2c936f89 100644 --- a/testing/auth_options_test.go +++ b/testing/auth_options_test.go @@ -1,7 +1,6 @@ package testing import ( - "reflect" "testing" "github.com/gophercloud/gophercloud/v2" @@ -199,6 +198,6 @@ func TestToTokenV3ScopeMap(t *testing.T) { } for _, failCase := range failCases { _, err := failCase.opts.ToTokenV3ScopeMap() - th.AssertDeepEquals(t, reflect.TypeOf(failCase.expected), reflect.TypeOf(err)) + th.AssertTypeEquals(t, failCase.expected, err) } } diff --git a/testing/params_test.go b/testing/params_test.go index 9e74bdd9ea..057a23b58a 100644 --- a/testing/params_test.go +++ b/testing/params_test.go @@ -2,7 +2,6 @@ package testing import ( "net/url" - "reflect" "testing" "time" @@ -255,7 +254,7 @@ func TestBuildRequestBody(t *testing.T) { for _, failCase := range failCases { _, err := gophercloud.BuildRequestBody(failCase.opts, "auth") - th.AssertDeepEquals(t, reflect.TypeOf(failCase.expected), reflect.TypeOf(err)) + th.AssertTypeEquals(t, failCase.expected, err) } createdAt := time.Date(2018, 1, 4, 10, 00, 12, 0, time.UTC) From 1d81d001a5c1fdb5ecb49001169186aab34f8496 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Fri, 31 May 2024 00:03:43 +0100 Subject: [PATCH 062/429] testing: Set test case names Make this a little easier to understand failures when they occur. Signed-off-by: Stephen Finucane --- testing/auth_options_test.go | 44 ++++++++++++++++++++---------------- testing/params_test.go | 22 ++++++++++++++---- 2 files changed, 42 insertions(+), 24 deletions(-) diff --git a/testing/auth_options_test.go b/testing/auth_options_test.go index fc2c936f89..67b06174e6 100644 --- a/testing/auth_options_test.go +++ b/testing/auth_options_test.go @@ -14,11 +14,12 @@ func TestToTokenV3ScopeMap(t *testing.T) { domainName := "Default" var successCases = []struct { + name string opts gophercloud.AuthOptions expected map[string]any }{ - // System-scoped { + "System-scoped", gophercloud.AuthOptions{ Scope: &gophercloud.AuthScope{ System: true, @@ -30,8 +31,8 @@ func TestToTokenV3ScopeMap(t *testing.T) { }, }, }, - // Trust-scoped { + "Trust-scoped", gophercloud.AuthOptions{ Scope: &gophercloud.AuthScope{ TrustID: "05144328-1f7d-46a9-a978-17eaad187077", @@ -43,8 +44,8 @@ func TestToTokenV3ScopeMap(t *testing.T) { }, }, }, - // Project-scoped (ID) { + "Project-scoped (ID)", gophercloud.AuthOptions{ Scope: &gophercloud.AuthScope{ ProjectID: projectID, @@ -56,8 +57,8 @@ func TestToTokenV3ScopeMap(t *testing.T) { }, }, }, - // Project-scoped (name) { + "Project-scoped (name)", gophercloud.AuthOptions{ Scope: &gophercloud.AuthScope{ ProjectName: projectName, @@ -73,8 +74,8 @@ func TestToTokenV3ScopeMap(t *testing.T) { }, }, }, - // Domain-scoped (ID) { + "Domain-scoped (ID)", gophercloud.AuthOptions{ Scope: &gophercloud.AuthScope{ DomainID: domainID, @@ -86,8 +87,8 @@ func TestToTokenV3ScopeMap(t *testing.T) { }, }, }, - // Domain-scoped (name) { + "Domain-scoped (name)", gophercloud.AuthOptions{ Scope: &gophercloud.AuthScope{ DomainName: domainName, @@ -99,8 +100,8 @@ func TestToTokenV3ScopeMap(t *testing.T) { }, }, }, - // Empty with project fallback (ID) { + "Empty with project fallback (ID)", gophercloud.AuthOptions{ TenantID: projectID, Scope: nil, @@ -111,8 +112,8 @@ func TestToTokenV3ScopeMap(t *testing.T) { }, }, }, - // Empty with project fallback (name) { + "Empty with project fallback (name)", gophercloud.AuthOptions{ TenantName: projectName, DomainName: domainName, @@ -127,8 +128,8 @@ func TestToTokenV3ScopeMap(t *testing.T) { }, }, }, - // Empty without fallback { + "Empty without fallback", gophercloud.AuthOptions{ Scope: nil, }, @@ -136,17 +137,20 @@ func TestToTokenV3ScopeMap(t *testing.T) { }, } for _, successCase := range successCases { - actual, err := successCase.opts.ToTokenV3ScopeMap() - th.AssertNoErr(t, err) - th.AssertDeepEquals(t, successCase.expected, actual) + t.Run(successCase.name, func(t *testing.T) { + actual, err := successCase.opts.ToTokenV3ScopeMap() + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, successCase.expected, actual) + }) } var failCases = []struct { + name string opts gophercloud.AuthOptions expected error }{ - // Project-scoped with name but missing domain ID/name { + "Project-scoped with name but missing domain ID/name", gophercloud.AuthOptions{ Scope: &gophercloud.AuthScope{ ProjectName: "admin", @@ -154,8 +158,8 @@ func TestToTokenV3ScopeMap(t *testing.T) { }, gophercloud.ErrScopeDomainIDOrDomainName{}, }, - // Project-scoped with both project name and project ID { + "Project-scoped with both project name and project ID", gophercloud.AuthOptions{ Scope: &gophercloud.AuthScope{ ProjectName: "admin", @@ -165,8 +169,8 @@ func TestToTokenV3ScopeMap(t *testing.T) { }, gophercloud.ErrScopeProjectIDOrProjectName{}, }, - // Project-scoped with name and unnecessary domain ID { + "Project-scoped with name and unnecessary domain ID", gophercloud.AuthOptions{ Scope: &gophercloud.AuthScope{ ProjectID: "685038cd-3c25-4faf-8f9b-78c18e503190", @@ -175,8 +179,8 @@ func TestToTokenV3ScopeMap(t *testing.T) { }, gophercloud.ErrScopeProjectIDAlone{}, }, - // Project-scoped with name and unnecessary domain name { + "Project-scoped with name and unnecessary domain name", gophercloud.AuthOptions{ Scope: &gophercloud.AuthScope{ ProjectID: "685038cd-3c25-4faf-8f9b-78c18e503190", @@ -185,8 +189,8 @@ func TestToTokenV3ScopeMap(t *testing.T) { }, gophercloud.ErrScopeProjectIDAlone{}, }, - // Domain-scoped with both domain name and domain ID { + "Domain-scoped with both domain name and domain ID", gophercloud.AuthOptions{ Scope: &gophercloud.AuthScope{ DomainID: "e4b515b8-e453-49d8-9cce-4bec244fa84e", @@ -197,7 +201,9 @@ func TestToTokenV3ScopeMap(t *testing.T) { }, } for _, failCase := range failCases { - _, err := failCase.opts.ToTokenV3ScopeMap() - th.AssertTypeEquals(t, failCase.expected, err) + t.Run(failCase.name, func(t *testing.T) { + _, err := failCase.opts.ToTokenV3ScopeMap() + th.AssertTypeEquals(t, failCase.expected, err) + }) } } diff --git a/testing/params_test.go b/testing/params_test.go index 057a23b58a..146fc27025 100644 --- a/testing/params_test.go +++ b/testing/params_test.go @@ -166,10 +166,12 @@ func TestBuildRequestBody(t *testing.T) { } var successCases = []struct { + name string opts AuthOptions expected map[string]any }{ { + "Password", AuthOptions{ PasswordCredentials: &PasswordCredentials{ Username: "me", @@ -186,6 +188,7 @@ func TestBuildRequestBody(t *testing.T) { }, }, { + "Token", AuthOptions{ TokenCredentials: &TokenCredentials{ ID: "1234567", @@ -202,16 +205,20 @@ func TestBuildRequestBody(t *testing.T) { } for _, successCase := range successCases { - actual, err := gophercloud.BuildRequestBody(successCase.opts, "auth") - th.AssertNoErr(t, err) - th.AssertDeepEquals(t, successCase.expected, actual) + t.Run(successCase.name, func(t *testing.T) { + actual, err := gophercloud.BuildRequestBody(successCase.opts, "auth") + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, successCase.expected, actual) + }) } var failCases = []struct { + name string opts AuthOptions expected error }{ { + "Conflicting tenant name and ID", AuthOptions{ TenantID: "987654321", TenantName: "me", @@ -219,6 +226,7 @@ func TestBuildRequestBody(t *testing.T) { gophercloud.ErrMissingInput{}, }, { + "Conflicting password and token auth", AuthOptions{ TokenCredentials: &TokenCredentials{ ID: "1234567", @@ -231,6 +239,7 @@ func TestBuildRequestBody(t *testing.T) { gophercloud.ErrMissingInput{}, }, { + "Missing Username or UserID", AuthOptions{ PasswordCredentials: &PasswordCredentials{ Password: "swordfish", @@ -239,6 +248,7 @@ func TestBuildRequestBody(t *testing.T) { gophercloud.ErrMissingInput{}, }, { + "Missing filler fields", AuthOptions{ PasswordCredentials: &PasswordCredentials{ Username: "me", @@ -253,8 +263,10 @@ func TestBuildRequestBody(t *testing.T) { } for _, failCase := range failCases { - _, err := gophercloud.BuildRequestBody(failCase.opts, "auth") - th.AssertTypeEquals(t, failCase.expected, err) + t.Run(failCase.name, func(t *testing.T) { + _, err := gophercloud.BuildRequestBody(failCase.opts, "auth") + th.AssertTypeEquals(t, failCase.expected, err) + }) } createdAt := time.Date(2018, 1, 4, 10, 00, 12, 0, time.UTC) From a9bd661231e4b862ea7ea5c33c927a88927b549a Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Fri, 31 May 2024 15:25:54 +0100 Subject: [PATCH 063/429] tests: Be consistent in our generation of credentials We were not passing through user IDs, despite our test wrappers indicating you could user either user IDs or usernames. Similarly, we were not always setting scope, which could cause issues when using a project ID. Correct all issues. We should eventually move this to another test helper but that's a job for a later change. Signed-off-by: Stephen Finucane --- internal/acceptance/openstack/client_test.go | 2 +- .../identity/v3/applicationcredentials_test.go | 4 ++-- .../openstack/identity/v3/credentials_test.go | 4 ++-- .../openstack/identity/v3/ec2credentials_test.go | 2 +- .../acceptance/openstack/identity/v3/oauth1_test.go | 2 +- .../acceptance/openstack/identity/v3/token_test.go | 10 +++++++++- .../acceptance/openstack/identity/v3/trusts_test.go | 7 +++++++ 7 files changed, 23 insertions(+), 8 deletions(-) diff --git a/internal/acceptance/openstack/client_test.go b/internal/acceptance/openstack/client_test.go index 7902961c55..69e9a09367 100644 --- a/internal/acceptance/openstack/client_test.go +++ b/internal/acceptance/openstack/client_test.go @@ -56,10 +56,10 @@ func TestEC2AuthMethod(t *testing.T) { authOptions := tokens.AuthOptions{ Username: ao.Username, + UserID: ao.UserID, Password: ao.Password, DomainName: ao.DomainName, DomainID: ao.DomainID, - // We need a scope to get the token roles list Scope: tokens.Scope{ ProjectID: ao.TenantID, ProjectName: ao.TenantName, diff --git a/internal/acceptance/openstack/identity/v3/applicationcredentials_test.go b/internal/acceptance/openstack/identity/v3/applicationcredentials_test.go index 1390e284a9..7a4ad01e1c 100644 --- a/internal/acceptance/openstack/identity/v3/applicationcredentials_test.go +++ b/internal/acceptance/openstack/identity/v3/applicationcredentials_test.go @@ -34,10 +34,10 @@ func TestApplicationCredentialsCRD(t *testing.T) { authOptions := tokens.AuthOptions{ Username: ao.Username, + UserID: ao.UserID, Password: ao.Password, DomainName: ao.DomainName, DomainID: ao.DomainID, - // We need a scope to get the token roles list Scope: tokens.Scope{ ProjectID: ao.TenantID, ProjectName: ao.TenantName, @@ -178,10 +178,10 @@ func TestApplicationCredentialsAccessRules(t *testing.T) { authOptions := tokens.AuthOptions{ Username: ao.Username, + UserID: ao.UserID, Password: ao.Password, DomainName: ao.DomainName, DomainID: ao.DomainID, - // We need a scope to get the token roles list Scope: tokens.Scope{ ProjectID: ao.TenantID, ProjectName: ao.TenantName, diff --git a/internal/acceptance/openstack/identity/v3/credentials_test.go b/internal/acceptance/openstack/identity/v3/credentials_test.go index a1167ac647..ce0362abee 100644 --- a/internal/acceptance/openstack/identity/v3/credentials_test.go +++ b/internal/acceptance/openstack/identity/v3/credentials_test.go @@ -24,10 +24,10 @@ func TestCredentialsCRUD(t *testing.T) { authOptions := tokens.AuthOptions{ Username: ao.Username, + UserID: ao.UserID, Password: ao.Password, DomainName: ao.DomainName, DomainID: ao.DomainID, - // We need a scope to get the token roles list Scope: tokens.Scope{ ProjectID: ao.TenantID, ProjectName: ao.TenantName, @@ -101,10 +101,10 @@ func TestCredentialsValidateS3(t *testing.T) { authOptions := tokens.AuthOptions{ Username: ao.Username, + UserID: ao.UserID, Password: ao.Password, DomainName: ao.DomainName, DomainID: ao.DomainID, - // We need a scope to get the token roles list Scope: tokens.Scope{ ProjectID: ao.TenantID, ProjectName: ao.TenantName, diff --git a/internal/acceptance/openstack/identity/v3/ec2credentials_test.go b/internal/acceptance/openstack/identity/v3/ec2credentials_test.go index 6500aa6f0c..7f27f51ed4 100644 --- a/internal/acceptance/openstack/identity/v3/ec2credentials_test.go +++ b/internal/acceptance/openstack/identity/v3/ec2credentials_test.go @@ -23,10 +23,10 @@ func TestEC2CredentialsCRD(t *testing.T) { authOptions := tokens.AuthOptions{ Username: ao.Username, + UserID: ao.UserID, Password: ao.Password, DomainName: ao.DomainName, DomainID: ao.DomainID, - // We need a scope to get the token roles list Scope: tokens.Scope{ ProjectID: ao.TenantID, ProjectName: ao.TenantName, diff --git a/internal/acceptance/openstack/identity/v3/oauth1_test.go b/internal/acceptance/openstack/identity/v3/oauth1_test.go index da6c8be148..7a93d43fb4 100644 --- a/internal/acceptance/openstack/identity/v3/oauth1_test.go +++ b/internal/acceptance/openstack/identity/v3/oauth1_test.go @@ -24,10 +24,10 @@ func TestOAuth1CRUD(t *testing.T) { authOptions := tokens.AuthOptions{ Username: ao.Username, + UserID: ao.UserID, Password: ao.Password, DomainName: ao.DomainName, DomainID: ao.DomainID, - // We need a scope to get the token roles list Scope: tokens.Scope{ ProjectID: ao.TenantID, ProjectName: ao.TenantName, diff --git a/internal/acceptance/openstack/identity/v3/token_test.go b/internal/acceptance/openstack/identity/v3/token_test.go index d5274ff6b1..1bc436caa7 100644 --- a/internal/acceptance/openstack/identity/v3/token_test.go +++ b/internal/acceptance/openstack/identity/v3/token_test.go @@ -24,8 +24,16 @@ func TestTokensGet(t *testing.T) { authOptions := tokens.AuthOptions{ Username: ao.Username, + UserID: ao.UserID, Password: ao.Password, - DomainName: "default", + DomainName: ao.DomainName, + DomainID: ao.DomainID, + Scope: tokens.Scope{ + ProjectID: ao.TenantID, + ProjectName: ao.TenantName, + DomainID: ao.DomainID, + DomainName: ao.DomainName, + }, } token, err := tokens.Create(context.TODO(), client, &authOptions).Extract() diff --git a/internal/acceptance/openstack/identity/v3/trusts_test.go b/internal/acceptance/openstack/identity/v3/trusts_test.go index 39c7191eea..2eb659d55b 100644 --- a/internal/acceptance/openstack/identity/v3/trusts_test.go +++ b/internal/acceptance/openstack/identity/v3/trusts_test.go @@ -29,9 +29,16 @@ func TestTrustCRUD(t *testing.T) { authOptions := tokens.AuthOptions{ Username: ao.Username, + UserID: ao.UserID, Password: ao.Password, DomainName: ao.DomainName, DomainID: ao.DomainID, + Scope: tokens.Scope{ + ProjectID: ao.TenantID, + ProjectName: ao.TenantName, + DomainID: ao.DomainID, + DomainName: ao.DomainName, + }, } token, err := tokens.Create(context.TODO(), client, &authOptions).Extract() From fb4700ae9b750281e92dc24b320ab77824381968 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Fri, 31 May 2024 15:29:19 +0100 Subject: [PATCH 064/429] tests: Add missing RequireAdmin calls We're clearly not testing with non-admin credentials. That would be a good future test but for now we simply fix the issues. Signed-off-by: Stephen Finucane --- .../acceptance/openstack/identity/v3/federation_test.go | 6 ++++-- internal/acceptance/openstack/identity/v3/oauth1_test.go | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/internal/acceptance/openstack/identity/v3/federation_test.go b/internal/acceptance/openstack/identity/v3/federation_test.go index b52d54cc30..35986dc15c 100644 --- a/internal/acceptance/openstack/identity/v3/federation_test.go +++ b/internal/acceptance/openstack/identity/v3/federation_test.go @@ -15,6 +15,8 @@ import ( ) func TestListMappings(t *testing.T) { + clients.RequireAdmin(t) + client, err := clients.NewIdentityV3Client() th.AssertNoErr(t, err) @@ -28,10 +30,10 @@ func TestListMappings(t *testing.T) { } func TestMappingsCRUD(t *testing.T) { - mappingName := tools.RandomString("TESTMAPPING-", 8) - clients.RequireAdmin(t) + mappingName := tools.RandomString("TESTMAPPING-", 8) + client, err := clients.NewIdentityV3Client() th.AssertNoErr(t, err) diff --git a/internal/acceptance/openstack/identity/v3/oauth1_test.go b/internal/acceptance/openstack/identity/v3/oauth1_test.go index 7a93d43fb4..125fdd0588 100644 --- a/internal/acceptance/openstack/identity/v3/oauth1_test.go +++ b/internal/acceptance/openstack/identity/v3/oauth1_test.go @@ -16,6 +16,8 @@ import ( ) func TestOAuth1CRUD(t *testing.T) { + clients.RequireAdmin(t) + client, err := clients.NewIdentityV3Client() th.AssertNoErr(t, err) From 7580d132d0eb2f558048664916a74d8eab25bcd8 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Fri, 31 May 2024 15:30:16 +0100 Subject: [PATCH 065/429] scripts: Add getenvvar tool Setting the necessary required environment variables has proven relatively tricky to do. Add a tool that will start doing this for us. Signed-off-by: Stephen Finucane --- script/getenvvar | 85 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100755 script/getenvvar diff --git a/script/getenvvar b/script/getenvvar new file mode 100755 index 0000000000..dbaa08f445 --- /dev/null +++ b/script/getenvvar @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 + +""" +Set environment variables required for the CI jobs by inspection of the +clouds.yaml file. This is useful where you only have this file. + +To set variables: + + $ eval $(./script/getenvvar) + +To unset them: + + $ unset $(compgen -v | grep OS_) +""" + +import argparse +from pathlib import Path +import sys + +import yaml + +p = Path('~/.config/openstack/clouds.yaml').expanduser() +parser = argparse.ArgumentParser() +parser.add_argument( + 'cloud', + help="Cloud to export credentials for", +) + +args = parser.parse_args() + +with p.open() as fh: + data = yaml.safe_load(fh) + +if args.cloud not in data.get('clouds', {}) or {}: + print(f'Could not find cloud {args.cloud} in {str(p)}', file=sys.stderr) + sys.exit(1) + +cloud = data['clouds'][args.cloud] + +if 'auth' not in cloud: + print(f'Missing auth section for cloud {cloud}', file=sys.stderr) + sys.exit(1) + +auth = cloud['auth'] + +if 'username' not in auth or 'password' not in auth: + print('Only password authentication supported', file=sys.stderr) + sys.exit(1) + +# FIXME: This should work but does not, since the check for auth credentials +# is just 'OS_USERNAME == admin' + +# user_id = auth.get('user_id') +# project_id = auth.get('project_id') +# if not user_id or not project_id: +# import openstack +# conn = openstack.connect(args.cloud) +# auth_ref = conn.config.get_auth().get_auth_ref(conn.session) +# +# if not user_id: +# user_id = auth_ref.user_id +# +# if not project_id: +# project_id = auth_ref.project_id +# +# result = f""" +# unset OS_CLOUD +# export OS_AUTH_URL={auth['auth_url']} +# export OS_USERID={user_id} +# export OS_PASSWORD={auth['password']} +# export OS_PROJECT_ID={project_id} +# export OS_REGION_NAME={cloud['region_name']} +# """.strip() + +result = f""" +unset OS_CLOUD +export OS_AUTH_URL={auth['auth_url']} +export OS_USERNAME={auth['username']} +export OS_PASSWORD={auth['password']} +export OS_PROJECT_NAME={auth['project_name']} +export OS_DOMAIN_ID={auth['user_domain_id']} +export OS_REGION_NAME={cloud['region_name']} +""" + +print(result) From fb846bdeccd110a44d1fed2423521ad90e227a4f Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Fri, 29 Nov 2024 11:13:38 +0000 Subject: [PATCH 066/429] make: Switch default test runner gotestsum provides far more readable output than the default runner. Signed-off-by: Stephen Finucane --- Makefile | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/Makefile b/Makefile index 128beec005..2a7a9376d9 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,7 @@ undefine GOFLAGS GOLANGCI_LINT_VERSION?=v1.57.1 +GO_TEST?=go run gotest.tools/gotestsum@latest --format testname ifeq ($(shell command -v podman 2> /dev/null),) RUNNER=docker @@ -26,84 +27,84 @@ lint: .PHONY: lint unit: - go test ./... + $(GO_TEST) ./... .PHONY: unit coverage: - go test -covermode count -coverprofile cover.out -coverpkg=./... ./... + $(GO_TEST) -covermode count -coverprofile cover.out -coverpkg=./... ./... .PHONY: coverage acceptance: acceptance-baremetal acceptance-blockstorage acceptance-compute acceptance-container acceptance-containerinfra acceptance-db acceptance-dns acceptance-identity acceptance-imageservice acceptance-keymanager acceptance-loadbalancer acceptance-messaging acceptance-networking acceptance-objectstorage acceptance-orchestration acceptance-placement acceptance-sharedfilesystems acceptance-workflow .PHONY: acceptance acceptance-baremetal: - go test -tags "fixtures acceptance" ./internal/acceptance/openstack/baremetal/... + $(GO_TEST) -tags "fixtures acceptance" ./internal/acceptance/openstack/baremetal/... .PHONY: acceptance-baremetal acceptance-blockstorage: - go test -tags "fixtures acceptance" ./internal/acceptance/openstack/blockstorage/... + $(GO_TEST) -tags "fixtures acceptance" ./internal/acceptance/openstack/blockstorage/... .PHONY: acceptance-blockstorage acceptance-compute: - go test -tags "fixtures acceptance" ./internal/acceptance/openstack/compute/... + $(GO_TEST) -tags "fixtures acceptance" ./internal/acceptance/openstack/compute/... .PHONY: acceptance-compute acceptance-container: - go test -tags "fixtures acceptance" ./internal/acceptance/openstack/container/... + $(GO_TEST) -tags "fixtures acceptance" ./internal/acceptance/openstack/container/... .PHONY: acceptance-container acceptance-containerinfra: - go test -tags "fixtures acceptance" ./internal/acceptance/openstack/containerinfra/... + $(GO_TEST) -tags "fixtures acceptance" ./internal/acceptance/openstack/containerinfra/... .PHONY: acceptance-containerinfra acceptance-db: - go test -tags "fixtures acceptance" ./internal/acceptance/openstack/db/... + $(GO_TEST) -tags "fixtures acceptance" ./internal/acceptance/openstack/db/... .PHONY: acceptance-db acceptance-dns: - go test -tags "fixtures acceptance" ./internal/acceptance/openstack/dns/... + $(GO_TEST) -tags "fixtures acceptance" ./internal/acceptance/openstack/dns/... .PHONY: acceptance-dns acceptance-identity: - go test -tags "fixtures acceptance" ./internal/acceptance/openstack/identity/... + $(GO_TEST) -tags "fixtures acceptance" ./internal/acceptance/openstack/identity/... .PHONY: acceptance-identity acceptance-image: - go test -tags "fixtures acceptance" ./internal/acceptance/openstack/imageservice/... + $(GO_TEST) -tags "fixtures acceptance" ./internal/acceptance/openstack/imageservice/... .PHONY: acceptance-image acceptance-keymanager: - go test -tags "fixtures acceptance" ./internal/acceptance/openstack/keymanager/... + $(GO_TEST) -tags "fixtures acceptance" ./internal/acceptance/openstack/keymanager/... .PHONY: acceptance-keymanager acceptance-loadbalancer: - go test -tags "fixtures acceptance" ./internal/acceptance/openstack/loadbalancer/... + $(GO_TEST) -tags "fixtures acceptance" ./internal/acceptance/openstack/loadbalancer/... .PHONY: acceptance-loadbalancer acceptance-messaging: - go test -tags "fixtures acceptance" ./internal/acceptance/openstack/messaging/... + $(GO_TEST) -tags "fixtures acceptance" ./internal/acceptance/openstack/messaging/... .PHONY: acceptance-messaging acceptance-networking: - go test -tags "fixtures acceptance" ./internal/acceptance/openstack/networking/... + $(GO_TEST) -tags "fixtures acceptance" ./internal/acceptance/openstack/networking/... .PHONY: acceptance-networking acceptance-objectstorage: - go test -tags "fixtures acceptance" ./internal/acceptance/openstack/objectstorage/... + $(GO_TEST) -tags "fixtures acceptance" ./internal/acceptance/openstack/objectstorage/... .PHONY: acceptance-objectstorage acceptance-orchestration: - go test -tags "fixtures acceptance" ./internal/acceptance/openstack/orchestration/... + $(GO_TEST) -tags "fixtures acceptance" ./internal/acceptance/openstack/orchestration/... .PHONY: acceptance-orchestration acceptance-placement: - go test -tags "fixtures acceptance" ./internal/acceptance/openstack/placement/... + $(GO_TEST) -tags "fixtures acceptance" ./internal/acceptance/openstack/placement/... .PHONY: acceptance-placement acceptance-sharedfilesystems: - go test -tags "fixtures acceptance" ./internal/acceptance/openstack/sharedfilesystems/... + $(GO_TEST) -tags "fixtures acceptance" ./internal/acceptance/openstack/sharedfilesystems/... .PHONY: acceptance-sharefilesystems acceptance-workflow: - go test -tags "fixtures acceptance" ./internal/acceptance/openstack/workflow/... + $(GO_TEST) -tags "fixtures acceptance" ./internal/acceptance/openstack/workflow/... .PHONY: acceptance-workflow From eff7d91cd2662c11fc70d37e77a92efa7d7a3ed3 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 10 Oct 2024 10:30:16 +0100 Subject: [PATCH 067/429] Add EndpointOpts.Aliases field, Types() method This allows us to request an endpoint by either its service type or one of its aliases. Signed-off-by: Stephen Finucane --- endpoint_search.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/endpoint_search.go b/endpoint_search.go index 2fbc3c97f1..cef845ab8c 100644 --- a/endpoint_search.go +++ b/endpoint_search.go @@ -30,8 +30,9 @@ const ( // package, like "openstack.NewComputeV2()". type EndpointOpts struct { // Type [required] is the service type for the client (e.g., "compute", - // "object-store"). Generally, this will be supplied by the service client - // function, but a user-given value will be honored if provided. + // "object-store"), as defined by the OpenStack Service Types Authority. + // This will generally be supplied by the service client function, but a + // user-given value will be honored if provided. Type string // Name [optional] is the service name for the client (e.g., "nova") as it @@ -39,6 +40,13 @@ type EndpointOpts struct { // different Name, which is why both Type and Name are sometimes needed. Name string + // Aliases [optional] is the set of aliases of the service type (e.g. + // "volumev2"/"volumev3", "volume" and "block-store" for the + // "block-storage" service type), as defined by the OpenStack Service Types + // Authority. As with Type, this will generally be supplied by the service + // client function, but a user-given value will be honored if provided. + Aliases []string + // Region [required] is the geographic region in which the endpoint resides, // generally specifying which datacenter should house your resources. // Required only for services that span multiple regions. @@ -74,3 +82,7 @@ func (eo *EndpointOpts) ApplyDefaults(t string) { eo.Availability = AvailabilityPublic } } + +func (eo *EndpointOpts) Types() []string { + return append([]string{eo.Type}, eo.Aliases...) +} From c507e2a9bf977d2bda06e55e9d0359baeaf11aa2 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 10 Oct 2024 11:21:53 +0100 Subject: [PATCH 068/429] Extend EndpointOpts.ApplyDefaults to set Aliases This demonstrates an unhappy path that we may wish to deprecate in the future, but no mechanism exists for doing aside from logging, which we don't do anywhere else. Signed-off-by: Stephen Finucane --- endpoint_search.go | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/endpoint_search.go b/endpoint_search.go index cef845ab8c..8818e769b8 100644 --- a/endpoint_search.go +++ b/endpoint_search.go @@ -1,5 +1,7 @@ package gophercloud +import "slices" + // Availability indicates to whom a specific service endpoint is accessible: // the internet at large, internal networks only, or only to administrators. // Different identity services use different terminology for these. Identity v2 @@ -22,6 +24,31 @@ const ( AvailabilityInternal Availability = "internal" ) +// ServiceTypeAliases contains a mapping of service types to any aliases, as +// defined by the OpenStack Service Types Authority. Only service types that +// we support are included. +var ServiceTypeAliases = map[string][]string{ + "application-container": {"container"}, + "baremetal": {"bare-metal"}, + "baremetal-introspection": {}, + "block-storage": {"block-store", "volume", "volumev2", "volumev3"}, + "compute": {}, + "container-infrastructure-management": {"container-infrastructure", "container-infra"}, + "database": {}, + "dns": {}, + "identity": {}, + "image": {}, + "key-manager": {}, + "load-balancer": {}, + "message": {"messaging"}, + "networking": {}, + "object-store": {}, + "orchestration": {}, + "placement": {}, + "shared-file-system": {"sharev2", "share"}, + "workflow": {"workflowv2"}, +} + // EndpointOpts specifies search criteria used by queries against an // OpenStack service catalog. The options must contain enough information to // unambiguously identify one, and only one, endpoint within the catalog. @@ -81,6 +108,24 @@ func (eo *EndpointOpts) ApplyDefaults(t string) { if eo.Availability == "" { eo.Availability = AvailabilityPublic } + if len(eo.Aliases) == 0 { + if aliases, ok := ServiceTypeAliases[eo.Type]; ok { + // happy path: user requested a service type by its official name + eo.Aliases = aliases + } else { + // unhappy path: user requested a service type by its alias or an + // invalid/unsupported service type + // TODO(stephenfin): This should probably be an error in v3 + for t, aliases := range ServiceTypeAliases { + if slices.Contains(aliases, eo.Type) { + // we intentionally override the service type, even if it + // was explicitly requested by the user + eo.Type = t + eo.Aliases = aliases + } + } + } + } } func (eo *EndpointOpts) Types() []string { From 0ba521aec71039e918235a4b5bbdeedbef732a7d Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 10 Oct 2024 10:54:09 +0100 Subject: [PATCH 069/429] Start respecting service types when searching for endpoints Signed-off-by: Stephen Finucane --- openstack/endpoint_location.go | 6 ++++-- testing/endpoint_search_test.go | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/openstack/endpoint_location.go b/openstack/endpoint_location.go index 2cdbd3e7f7..14cff0d755 100644 --- a/openstack/endpoint_location.go +++ b/openstack/endpoint_location.go @@ -1,6 +1,8 @@ package openstack import ( + "slices" + "github.com/gophercloud/gophercloud/v2" tokens2 "github.com/gophercloud/gophercloud/v2/openstack/identity/v2/tokens" tokens3 "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/tokens" @@ -20,7 +22,7 @@ func V2EndpointURL(catalog *tokens2.ServiceCatalog, opts gophercloud.EndpointOpt // Extract Endpoints from the catalog entries that match the requested Type, Name if provided, and Region if provided. var endpoints = make([]tokens2.Endpoint, 0, 1) for _, entry := range catalog.Entries { - if (entry.Type == opts.Type) && (opts.Name == "" || entry.Name == opts.Name) { + if (slices.Contains(opts.Types(), entry.Type)) && (opts.Name == "" || entry.Name == opts.Name) { for _, endpoint := range entry.Endpoints { if opts.Region == "" || endpoint.Region == opts.Region { endpoints = append(endpoints, endpoint) @@ -74,7 +76,7 @@ func V3EndpointURL(catalog *tokens3.ServiceCatalog, opts gophercloud.EndpointOpt // Name if provided, and Region if provided. var endpoints = make([]tokens3.Endpoint, 0, 1) for _, entry := range catalog.Entries { - if (entry.Type == opts.Type) && (opts.Name == "" || entry.Name == opts.Name) { + if (slices.Contains(opts.Types(), entry.Type)) && (opts.Name == "" || entry.Name == opts.Name) { for _, endpoint := range entry.Endpoints { if opts.Availability != gophercloud.AvailabilityAdmin && opts.Availability != gophercloud.AvailabilityPublic && diff --git a/testing/endpoint_search_test.go b/testing/endpoint_search_test.go index 278955ecdf..c1ae9b92db 100644 --- a/testing/endpoint_search_test.go +++ b/testing/endpoint_search_test.go @@ -10,11 +10,11 @@ import ( func TestApplyDefaultsToEndpointOpts(t *testing.T) { eo := gophercloud.EndpointOpts{Availability: gophercloud.AvailabilityPublic} eo.ApplyDefaults("compute") - expected := gophercloud.EndpointOpts{Availability: gophercloud.AvailabilityPublic, Type: "compute"} + expected := gophercloud.EndpointOpts{Availability: gophercloud.AvailabilityPublic, Type: "compute", Aliases: []string{}} th.CheckDeepEquals(t, expected, eo) eo = gophercloud.EndpointOpts{Type: "compute"} eo.ApplyDefaults("object-store") - expected = gophercloud.EndpointOpts{Availability: gophercloud.AvailabilityPublic, Type: "compute"} + expected = gophercloud.EndpointOpts{Availability: gophercloud.AvailabilityPublic, Type: "compute", Aliases: []string{}} th.CheckDeepEquals(t, expected, eo) } From e3947338f69b8b52bd494f09388152febc49c6aa Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 10 Oct 2024 11:08:33 +0100 Subject: [PATCH 070/429] Use official service types We now have alias support and Gophercloud will automatically negotiate on our behalf. This means we set the service types to their official value rather than one of the aliases. Signed-off-by: Stephen Finucane --- openstack/blockstorage/noauth/requests.go | 4 ++-- openstack/client.go | 16 +++++++++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/openstack/blockstorage/noauth/requests.go b/openstack/blockstorage/noauth/requests.go index 87f2d9b7f9..cf887553f0 100644 --- a/openstack/blockstorage/noauth/requests.go +++ b/openstack/blockstorage/noauth/requests.go @@ -51,10 +51,10 @@ func initClientOpts(client *gophercloud.ProviderClient, eo EndpointOpts, clientT // NewBlockStorageNoAuthV2 creates a ServiceClient that may be used to access "noauth" v2 block storage service. func NewBlockStorageNoAuthV2(client *gophercloud.ProviderClient, eo EndpointOpts) (*gophercloud.ServiceClient, error) { - return initClientOpts(client, eo, "volumev2") + return initClientOpts(client, eo, "block-storage") } // NewBlockStorageNoAuthV3 creates a ServiceClient that may be used to access "noauth" v3 block storage service. func NewBlockStorageNoAuthV3(client *gophercloud.ProviderClient, eo EndpointOpts) (*gophercloud.ServiceClient, error) { - return initClientOpts(client, eo, "volumev3") + return initClientOpts(client, eo, "block-storage") } diff --git a/openstack/client.go b/openstack/client.go index 43b569d3b4..122a3ee699 100644 --- a/openstack/client.go +++ b/openstack/client.go @@ -344,6 +344,7 @@ func NewIdentityV3(client *gophercloud.ProviderClient, eo gophercloud.EndpointOp }, nil } +// TODO(stephenfin): Allow passing aliases to all New${SERVICE}V${VERSION} methods in v3 func initClientOpts(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts, clientType string) (*gophercloud.ServiceClient, error) { sc := new(gophercloud.ServiceClient) eo.ApplyDefaults(clientType) @@ -393,6 +394,7 @@ func NewNetworkV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpt return sc, err } +// TODO(stephenfin): Remove this in v3. We no longer support the V1 Block Storage service. // NewBlockStorageV1 creates a ServiceClient that may be used to access the v1 // block storage service. func NewBlockStorageV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { @@ -402,17 +404,17 @@ func NewBlockStorageV1(client *gophercloud.ProviderClient, eo gophercloud.Endpoi // NewBlockStorageV2 creates a ServiceClient that may be used to access the v2 // block storage service. func NewBlockStorageV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { - return initClientOpts(client, eo, "volumev2") + return initClientOpts(client, eo, "block-storage") } // NewBlockStorageV3 creates a ServiceClient that may be used to access the v3 block storage service. func NewBlockStorageV3(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { - return initClientOpts(client, eo, "volumev3") + return initClientOpts(client, eo, "block-storage") } // NewSharedFileSystemV2 creates a ServiceClient that may be used to access the v2 shared file system service. func NewSharedFileSystemV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { - return initClientOpts(client, eo, "sharev2") + return initClientOpts(client, eo, "shared-file-system") } // NewOrchestrationV1 creates a ServiceClient that may be used to access the v1 @@ -457,14 +459,14 @@ func NewLoadBalancerV2(client *gophercloud.ProviderClient, eo gophercloud.Endpoi // NewMessagingV2 creates a ServiceClient that may be used with the v2 messaging // service. func NewMessagingV2(client *gophercloud.ProviderClient, clientID string, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { - sc, err := initClientOpts(client, eo, "messaging") + sc, err := initClientOpts(client, eo, "message") sc.MoreHeaders = map[string]string{"Client-ID": clientID} return sc, err } // NewContainerV1 creates a ServiceClient that may be used with v1 container package func NewContainerV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { - return initClientOpts(client, eo, "container") + return initClientOpts(client, eo, "application-container") } // NewKeyManagerV1 creates a ServiceClient that may be used with the v1 key @@ -478,12 +480,12 @@ func NewKeyManagerV1(client *gophercloud.ProviderClient, eo gophercloud.Endpoint // NewContainerInfraV1 creates a ServiceClient that may be used with the v1 container infra management // package. func NewContainerInfraV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { - return initClientOpts(client, eo, "container-infra") + return initClientOpts(client, eo, "container-infrastructure-management") } // NewWorkflowV2 creates a ServiceClient that may be used with the v2 workflow management package. func NewWorkflowV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { - return initClientOpts(client, eo, "workflowv2") + return initClientOpts(client, eo, "workflow") } // NewPlacementV1 creates a ServiceClient that may be used with the placement package. From 5a3e9f6c82ea7c66c460653ef0abd5a1e18e47ee Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Fri, 29 Nov 2024 14:21:46 +0000 Subject: [PATCH 071/429] Set correct service name for microversion header Despite the official service type being block-storage, cinder only accepts volume as the service type in the OpenStack-API-Version header :( Signed-off-by: Stephen Finucane --- service_client.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/service_client.go b/service_client.go index 11b80108c3..c1f9f41d4d 100644 --- a/service_client.go +++ b/service_client.go @@ -115,13 +115,17 @@ func (client *ServiceClient) Head(ctx context.Context, url string, opts *Request } func (client *ServiceClient) setMicroversionHeader(opts *RequestOpts) { + serviceType := client.Type + switch client.Type { case "compute": opts.MoreHeaders["X-OpenStack-Nova-API-Version"] = client.Microversion - case "sharev2": + case "shared-file-system", "sharev2", "share": opts.MoreHeaders["X-OpenStack-Manila-API-Version"] = client.Microversion - case "volume": + case "block-storage", "block-store", "volume", "volumev3": opts.MoreHeaders["X-OpenStack-Volume-API-Version"] = client.Microversion + // cinder should accept block-storage but (as of Dalmatian) does not + serviceType = "volume" case "baremetal": opts.MoreHeaders["X-OpenStack-Ironic-API-Version"] = client.Microversion case "baremetal-introspection": @@ -129,7 +133,7 @@ func (client *ServiceClient) setMicroversionHeader(opts *RequestOpts) { } if client.Type != "" { - opts.MoreHeaders["OpenStack-API-Version"] = client.Type + " " + client.Microversion + opts.MoreHeaders["OpenStack-API-Version"] = serviceType + " " + client.Microversion } } From eaf292310871e42f3bb09e2aaeb32d804f6a46fa Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Wed, 17 Jul 2024 12:41:23 +0100 Subject: [PATCH 072/429] lint: Address recent lint issues We really need to run golangci-lint in the gate but fix these issues for now. Signed-off-by: Stephen Finucane --- .../extensions/bgpvpns/testing/requests_test.go | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/openstack/networking/v2/extensions/bgpvpns/testing/requests_test.go b/openstack/networking/v2/extensions/bgpvpns/testing/requests_test.go index 859441f6f4..3b39e7cee0 100644 --- a/openstack/networking/v2/extensions/bgpvpns/testing/requests_test.go +++ b/openstack/networking/v2/extensions/bgpvpns/testing/requests_test.go @@ -27,7 +27,9 @@ func TestList(t *testing.T) { th.TestMethod(t, r, "GET") th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) - r.ParseForm() + if err := r.ParseForm(); err != nil { + t.Errorf("Failed to parse request form %v", err) + } th.AssertDeepEquals(t, r.Form["fields"], fields) th.AssertDeepEquals(t, r.Form["project_id"], filterProjectID) @@ -177,7 +179,9 @@ func TestListNetworkAssociations(t *testing.T) { th.TestMethod(t, r, "GET") th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) - r.ParseForm() + if err := r.ParseForm(); err != nil { + t.Errorf("Failed to parse request form %v", err) + } th.AssertDeepEquals(t, fields, r.Form["fields"]) w.Header().Add("Content-Type", "application/json") @@ -278,7 +282,9 @@ func TestListRouterAssociations(t *testing.T) { th.TestMethod(t, r, "GET") th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) - r.ParseForm() + if err := r.ParseForm(); err != nil { + t.Errorf("Failed to parse request form %v", err) + } th.AssertDeepEquals(t, fields, r.Form["fields"]) w.Header().Add("Content-Type", "application/json") @@ -404,7 +410,9 @@ func TestListPortAssociations(t *testing.T) { th.TestMethod(t, r, "GET") th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) - r.ParseForm() + if err := r.ParseForm(); err != nil { + t.Errorf("Failed to parse request form %v", err) + } th.AssertDeepEquals(t, fields, r.Form["fields"]) w.Header().Add("Content-Type", "application/json") From ce56d121f0139488477330743b89bad1cd244964 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Fri, 29 Nov 2024 14:39:32 +0000 Subject: [PATCH 073/429] lint: Remove non-constant format string in calls (govet) We were incorrectly using 'fmt.Printf', 'fmt.Errorf' and 't.Logf' with non-template strings/no arguments. The fix to this is replace these calls with the non-suffixed variants. There are many users of 'fmt.Fprint' - too many to do by hand - so this replacement was resolved using 'sed': sed 's/Fprintf/Fprint/g' -i $(ag fmt.Fprintf -l) We then manually fix the 25 cases where 'fmt.Fprintf' is actually warranted and manually replaced the errant users of 'fmt.Errorf' and 't.Logf'. We also rework 'internal/acceptance/clients/clients.go' slightly to make the code a bit clearer. PS: This is apparently going to be an issue in go 1.24 (specifically in 'go vet') [1] so this is not just golangci-lint being annoying. @PierrePrinetti, that's directed at you ;) [1] https://github.com/golang/go/issues/60529 Signed-off-by: Stephen Finucane --- internal/acceptance/clients/clients.go | 16 +++---- internal/acceptance/tools/tools.go | 2 +- .../apiversions/testing/fixtures_test.go | 4 +- .../v1/allocations/testing/fixtures_test.go | 8 ++-- .../v1/conductors/testing/fixtures_test.go | 8 ++-- .../v1/drivers/testing/fixtures_test.go | 8 ++-- .../v1/nodes/testing/fixtures_test.go | 38 +++++++-------- .../v1/ports/testing/fixtures_test.go | 12 ++--- .../v1/introspection/testing/fixtures.go | 8 ++-- .../apiversions/testing/fixtures_test.go | 4 +- .../testing/fixtures_test.go | 2 +- .../v2/backups/testing/fixtures_test.go | 14 +++--- .../v2/limits/testing/fixtures_test.go | 2 +- .../v2/quotasets/testing/fixtures_test.go | 2 +- .../schedulerstats/testing/fixtures_test.go | 4 +- .../v2/services/testing/fixtures_test.go | 2 +- .../v2/snapshots/testing/fixtures_test.go | 8 ++-- .../v2/transfers/testing/fixtures_test.go | 8 ++-- .../v2/volumes/testing/fixtures_test.go | 30 ++++++------ .../v3/attachments/testing/fixtures_test.go | 10 ++-- .../testing/fixtures_test.go | 2 +- .../v3/backups/testing/fixtures_test.go | 14 +++--- .../v3/limits/testing/fixtures_test.go | 2 +- .../v3/qos/testing/fixtures_test.go | 10 ++-- .../v3/quotasets/testing/fixtures_test.go | 2 +- .../schedulerstats/testing/fixtures_test.go | 4 +- .../v3/services/testing/fixtures_test.go | 2 +- .../v3/snapshots/testing/fixtures_test.go | 10 ++-- .../v3/transfers/testing/fixtures_test.go | 8 ++-- .../v3/volumes/testing/fixtures_test.go | 32 ++++++------- .../v3/volumetypes/testing/fixtures_test.go | 24 +++++----- .../v3/volumetypes/testing/requests_test.go | 2 +- .../common/extensions/testing/fixtures.go | 4 +- .../apiversions/testing/fixtures_test.go | 6 +-- .../v2/aggregates/testing/fixtures_test.go | 14 +++--- .../attachinterfaces/testing/fixtures_test.go | 6 +-- .../testing/fixtures_test.go | 4 +- .../v2/extensions/testing/fixtures_test.go | 4 +- .../v2/flavors/testing/fixtures_test.go | 8 ++-- .../v2/flavors/testing/requests_test.go | 14 +++--- .../v2/hypervisors/testing/fixtures_test.go | 16 +++---- .../instanceactions/testing/fixtures_test.go | 4 +- .../v2/keypairs/testing/fixtures_test.go | 12 ++--- .../v2/limits/testing/fixtures_test.go | 2 +- .../v2/quotasets/testing/fixtures_test.go | 8 ++-- .../remoteconsoles/testing/requests_test.go | 2 +- .../v2/secgroups/testing/fixtures_test.go | 14 +++--- .../v2/servergroups/testing/fixtures_test.go | 10 ++-- .../v2/servers/testing/fixtures_test.go | 46 +++++++++--------- .../v2/services/testing/fixtures_test.go | 6 +-- .../compute/v2/tags/testing/requests_test.go | 4 +- .../v2/volumeattach/testing/fixtures_test.go | 6 +-- .../v1/capsules/testing/fixtures_test.go | 10 ++-- .../apiversions/testing/fixtures_test.go | 4 +- .../v1/certificates/testing/fixtures_test.go | 2 +- .../v1/nodegroups/testing/fixtures_test.go | 22 ++++----- .../v2/recordsets/testing/fixtures_test.go | 12 ++--- .../transfer/accept/testing/fixtures_test.go | 8 ++-- .../transfer/request/testing/fixtures_test.go | 8 ++-- .../dns/v2/zones/testing/fixtures_test.go | 10 ++-- .../v2/extensions/testing/fixtures_test.go | 2 +- .../v2/roles/testing/fixtures_test.go | 2 +- .../v2/tenants/testing/fixtures_test.go | 8 ++-- .../v2/tokens/testing/fixtures_test.go | 4 +- .../v2/users/testing/fixtures_test.go | 10 ++-- .../testing/fixtures_test.go | 14 +++--- .../v3/catalog/testing/fixtures_test.go | 2 +- .../v3/credentials/testing/fixtures_test.go | 8 ++-- .../v3/domains/testing/fixtures_test.go | 10 ++-- .../ec2credentials/testing/fixtures_test.go | 6 +-- .../v3/ec2tokens/testing/requests_test.go | 2 +- .../v3/endpoints/testing/requests_test.go | 6 +-- .../v3/federation/testing/fixtures_test.go | 8 ++-- .../v3/groups/testing/fixtures_test.go | 8 ++-- .../v3/limits/testing/fixtures_test.go | 10 ++-- .../v3/oauth1/testing/fixtures_test.go | 24 +++++----- .../v3/policies/testing/fixtures_test.go | 10 ++-- .../projectendpoints/testing/requests_test.go | 2 +- .../v3/projects/testing/fixtures_test.go | 14 +++--- .../v3/regions/testing/fixtures_test.go | 8 ++-- .../registeredlimits/testing/fixtures_test.go | 8 ++-- .../v3/roles/testing/fixtures_test.go | 28 +++++------ .../v3/services/testing/fixtures_test.go | 8 ++-- .../v3/tokens/testing/requests_test.go | 10 ++-- .../v3/trusts/testing/fixtures_test.go | 12 ++--- .../v3/users/testing/fixtures_test.go | 16 +++---- .../v2/imageimport/testing/requests_test.go | 4 +- .../image/v2/images/testing/fixtures_test.go | 16 +++---- .../image/v2/members/testing/fixtures_test.go | 10 ++-- .../image/v2/tasks/testing/requests_test.go | 6 +-- .../v1/acls/testing/fixtures_test.go | 12 ++--- .../v1/containers/testing/fixtures_test.go | 12 ++--- .../v1/orders/testing/fixtures_test.go | 6 +-- .../v1/secrets/testing/fixtures_test.go | 18 +++---- .../v2/amphorae/testing/fixtures_test.go | 6 +-- .../v2/apiversions/testing/fixture.go | 2 +- .../v2/flavorprofiles/testing/fixtures.go | 10 ++-- .../v2/flavors/testing/fixtures.go | 10 ++-- .../v2/flavors/testing/requests_test.go | 2 +- .../v2/l7policies/testing/fixtures_test.go | 22 ++++----- .../v2/listeners/testing/fixtures_test.go | 12 ++--- .../v2/loadbalancers/testing/fixtures_test.go | 16 +++---- .../v2/monitors/testing/fixtures_test.go | 10 ++-- .../v2/pools/testing/fixtures_test.go | 20 ++++---- .../v2/providers/testing/fixtures_test.go | 2 +- .../v2/quotas/testing/requests_test.go | 8 ++-- .../v2/claims/testing/fixtures_test.go | 4 +- .../v2/messages/testing/fixtures_test.go | 10 ++-- .../v2/queues/testing/fixtures_test.go | 10 ++-- .../v2/apiversions/testing/requests_test.go | 4 +- .../agents/testing/requests_test.go | 14 +++--- .../attributestags/testing/requests_test.go | 4 +- .../bgp/peers/testing/requests_test.go | 8 ++-- .../bgp/speakers/testing/requests_test.go | 18 +++---- .../bgpvpns/testing/requests_test.go | 30 ++++++------ .../extensions/dns/testing/fixtures_test.go | 22 ++++----- .../external/testing/results_test.go | 8 ++-- .../fwaas_v2/groups/testing/requests_test.go | 12 ++--- .../policies/testing/requests_test.go | 12 ++--- .../fwaas_v2/rules/testing/requests_test.go | 10 ++-- .../addressscopes/testing/requests_test.go | 8 ++-- .../extraroutes/testing/requests_test.go | 4 +- .../floatingips/testing/requests_test.go | 16 +++---- .../portforwarding/testing/requests_test.go | 8 ++-- .../layer3/routers/testing/requests_test.go | 18 +++---- .../v2/extensions/mtu/testing/results_test.go | 8 ++-- .../testing/requests_test.go | 4 +- .../portsbinding/testing/fixtures_test.go | 8 ++-- .../provider/testing/results_test.go | 10 ++-- .../qos/policies/testing/requests_test.go | 24 +++++----- .../qos/rules/testing/requests_test.go | 24 +++++----- .../qos/ruletypes/testing/requests_test.go | 2 +- .../quotas/testing/requests_test.go | 6 +-- .../rbacpolicies/testing/requests_test.go | 10 ++-- .../security/groups/testing/requests_test.go | 8 ++-- .../security/rules/testing/requests_test.go | 8 ++-- .../subnetpools/testing/requests_test.go | 8 ++-- .../v2/extensions/testing/delegate_test.go | 4 +- .../trunks/testing/requests_test.go | 16 +++---- .../vlantransparent/testing/requests_test.go | 8 ++-- .../endpointgroups/testing/requests_test.go | 8 ++-- .../ikepolicies/testing/requests_test.go | 8 ++-- .../ipsecpolicies/testing/requests_test.go | 8 ++-- .../vpnaas/services/testing/requests_test.go | 8 ++-- .../siteconnections/testing/requests_test.go | 8 ++-- .../v2/networks/testing/requests_test.go | 22 ++++----- .../v2/ports/testing/requests_test.go | 48 +++++++++---------- .../v2/subnets/testing/requests_test.go | 32 ++++++------- .../v1/containers/testing/fixtures.go | 8 ++-- .../v1/objects/testing/fixtures_test.go | 12 ++--- .../v1/swauth/testing/fixtures_test.go | 2 +- .../v1/apiversions/testing/requests_test.go | 2 +- .../v1/buildinfo/testing/fixtures_test.go | 2 +- .../v1/stackevents/testing/fixtures_test.go | 12 ++--- .../stackresources/testing/fixtures_test.go | 16 +++---- .../v1/stacks/testing/fixtures_test.go | 14 +++--- .../orchestration/v1/stacks/utils_test.go | 2 +- .../stacktemplates/testing/fixtures_test.go | 4 +- .../testing/fixtures_test.go | 16 +++---- .../apiversions/testing/fixtures_test.go | 8 ++-- .../testing/fixtures_test.go | 2 +- .../v2/errors/testing/fixtures_test.go | 2 +- .../v2/messages/testing/fixtures_test.go | 6 +-- .../v2/replicas/testing/fixtures_test.go | 8 ++-- .../schedulerstats/testing/fixtures_test.go | 4 +- .../securityservices/testing/fixtures_test.go | 10 ++-- .../v2/services/testing/fixtures_test.go | 2 +- .../shareaccessrules/testing/fixtures_test.go | 2 +- .../shareaccessrules/testing/requests_test.go | 2 +- .../v2/sharenetworks/testing/fixtures_test.go | 24 +++++----- .../v2/shares/testing/fixtures_test.go | 14 +++--- .../sharetransfers/testing/fixtures_test.go | 8 ++-- .../v2/sharetypes/testing/fixtures_test.go | 12 ++--- .../v2/snapshots/testing/fixtures_test.go | 6 +-- openstack/testing/client_test.go | 6 +-- .../v2/crontriggers/testing/requests_test.go | 6 +-- .../v2/executions/testing/requests_test.go | 6 +-- .../v2/workflows/testing/requests_test.go | 10 ++-- pagination/testing/linked_test.go | 2 +- pagination/testing/marker_test.go | 6 +-- pagination/testing/single_test.go | 2 +- testhelper/fixture/helper.go | 2 +- testing/provider_client_test.go | 4 +- 183 files changed, 882 insertions(+), 884 deletions(-) diff --git a/internal/acceptance/clients/clients.go b/internal/acceptance/clients/clients.go index 21be9dbea2..f981ffcea2 100644 --- a/internal/acceptance/clients/clients.go +++ b/internal/acceptance/clients/clients.go @@ -107,16 +107,14 @@ func AcceptanceTestChoicesFromEnv() (*AcceptanceTestChoices, error) { notDistinct = "OS_FLAVOR_ID and OS_FLAVOR_ID_RESIZE must be distinct." } - if len(missing) > 0 || notDistinct != "" { - text := "You're missing some important setup:\n" - if len(missing) > 0 { - text += " * These environment variables must be provided: " + strings.Join(missing, ", ") + "\n" - } - if notDistinct != "" { - text += " * " + notDistinct + "\n" - } + if len(missing) > 0 { + text := "You're missing some important setup:\n * These environment variables must be provided: %s\n" + return nil, fmt.Errorf(text, strings.Join(missing, ", ")) + } - return nil, fmt.Errorf(text) + if notDistinct != "" { + text := "You're missing some important setup:\n * %s\n" + return nil, fmt.Errorf(text, notDistinct) } return &AcceptanceTestChoices{ diff --git a/internal/acceptance/tools/tools.go b/internal/acceptance/tools/tools.go index 8b0fad2ea6..75ac004473 100644 --- a/internal/acceptance/tools/tools.go +++ b/internal/acceptance/tools/tools.go @@ -81,5 +81,5 @@ func Elide(value string) string { // PrintResource returns a resource as a readable structure func PrintResource(t *testing.T, resource any) { b, _ := json.MarshalIndent(resource, "", " ") - t.Logf(string(b)) + t.Log(string(b)) } diff --git a/openstack/baremetal/apiversions/testing/fixtures_test.go b/openstack/baremetal/apiversions/testing/fixtures_test.go index 5e169d36fc..d0e11553c2 100644 --- a/openstack/baremetal/apiversions/testing/fixtures_test.go +++ b/openstack/baremetal/apiversions/testing/fixtures_test.go @@ -89,7 +89,7 @@ func MockListResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, IronicAPIAllVersionResponse) + fmt.Fprint(w, IronicAPIAllVersionResponse) }) } @@ -101,6 +101,6 @@ func MockGetResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, IronicAPIVersionResponse) + fmt.Fprint(w, IronicAPIVersionResponse) }) } diff --git a/openstack/baremetal/v1/allocations/testing/fixtures_test.go b/openstack/baremetal/v1/allocations/testing/fixtures_test.go index 6b8655169b..7ee9fa4834 100644 --- a/openstack/baremetal/v1/allocations/testing/fixtures_test.go +++ b/openstack/baremetal/v1/allocations/testing/fixtures_test.go @@ -120,10 +120,10 @@ func HandleAllocationListSuccessfully(t *testing.T) { marker := r.Form.Get("marker") switch marker { case "": - fmt.Fprintf(w, AllocationListBody) + fmt.Fprint(w, AllocationListBody) case "eff80f47-75f0-4d41-b1aa-cf07c201adac": - fmt.Fprintf(w, `{ "allocations": [] }`) + fmt.Fprint(w, `{ "allocations": [] }`) default: t.Fatalf("/allocations invoked with unexpected marker=[%s]", marker) } @@ -145,7 +145,7 @@ func HandleAllocationCreationSuccessfully(t *testing.T, response string) { w.WriteHeader(http.StatusAccepted) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, response) + fmt.Fprint(w, response) }) } @@ -165,6 +165,6 @@ func HandleAllocationGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestHeader(t, r, "Accept", "application/json") - fmt.Fprintf(w, SingleAllocationBody) + fmt.Fprint(w, SingleAllocationBody) }) } diff --git a/openstack/baremetal/v1/conductors/testing/fixtures_test.go b/openstack/baremetal/v1/conductors/testing/fixtures_test.go index 8e59ddaab4..fd66a34d4b 100644 --- a/openstack/baremetal/v1/conductors/testing/fixtures_test.go +++ b/openstack/baremetal/v1/conductors/testing/fixtures_test.go @@ -150,10 +150,10 @@ func HandleConductorListSuccessfully(t *testing.T) { marker := r.Form.Get("marker") switch marker { case "": - fmt.Fprintf(w, ConductorListBody) + fmt.Fprint(w, ConductorListBody) case "9e5476bd-a4ec-4653-93d6-72c93aa682ba": - fmt.Fprintf(w, `{ "servers": [] }`) + fmt.Fprint(w, `{ "servers": [] }`) default: t.Fatalf("/conductors invoked with unexpected marker=[%s]", marker) } @@ -170,7 +170,7 @@ func HandleConductorListDetailSuccessfully(t *testing.T) { t.Errorf("Failed to parse request form %v", err) } - fmt.Fprintf(w, ConductorListDetailBody) + fmt.Fprint(w, ConductorListDetailBody) }) } @@ -180,6 +180,6 @@ func HandleConductorGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestHeader(t, r, "Accept", "application/json") - fmt.Fprintf(w, SingleConductorBody) + fmt.Fprint(w, SingleConductorBody) }) } diff --git a/openstack/baremetal/v1/drivers/testing/fixtures_test.go b/openstack/baremetal/v1/drivers/testing/fixtures_test.go index a06bcee928..6c6d0fcc7e 100644 --- a/openstack/baremetal/v1/drivers/testing/fixtures_test.go +++ b/openstack/baremetal/v1/drivers/testing/fixtures_test.go @@ -377,7 +377,7 @@ func HandleListDriversSuccessfully(t *testing.T) { t.Errorf("Failed to parse request form %v", err) } - fmt.Fprintf(w, ListDriversBody) + fmt.Fprint(w, ListDriversBody) }) } @@ -388,7 +388,7 @@ func HandleGetDriverDetailsSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestHeader(t, r, "Accept", "application/json") - fmt.Fprintf(w, SingleDriverDetails) + fmt.Fprint(w, SingleDriverDetails) }) } @@ -399,7 +399,7 @@ func HandleGetDriverPropertiesSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestHeader(t, r, "Accept", "application/json") - fmt.Fprintf(w, SingleDriverProperties) + fmt.Fprint(w, SingleDriverProperties) }) } @@ -410,6 +410,6 @@ func HandleGetDriverDiskPropertiesSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestHeader(t, r, "Accept", "application/json") - fmt.Fprintf(w, SingleDriverDiskProperties) + fmt.Fprint(w, SingleDriverDiskProperties) }) } diff --git a/openstack/baremetal/v1/nodes/testing/fixtures_test.go b/openstack/baremetal/v1/nodes/testing/fixtures_test.go index d174edde2b..10589c5f1b 100644 --- a/openstack/baremetal/v1/nodes/testing/fixtures_test.go +++ b/openstack/baremetal/v1/nodes/testing/fixtures_test.go @@ -1404,10 +1404,10 @@ func HandleNodeListSuccessfully(t *testing.T) { marker := r.Form.Get("marker") switch marker { case "": - fmt.Fprintf(w, NodeListBody) + fmt.Fprint(w, NodeListBody) case "9e5476bd-a4ec-4653-93d6-72c93aa682ba": - fmt.Fprintf(w, `{ "servers": [] }`) + fmt.Fprint(w, `{ "servers": [] }`) default: t.Fatalf("/nodes invoked with unexpected marker=[%s]", marker) } @@ -1424,7 +1424,7 @@ func HandleNodeListDetailSuccessfully(t *testing.T) { t.Errorf("Failed to parse request form %v", err) } - fmt.Fprintf(w, NodeListDetailBody) + fmt.Fprint(w, NodeListDetailBody) }) } @@ -1451,7 +1451,7 @@ func HandleNodeCreationSuccessfully(t *testing.T, response string) { w.WriteHeader(http.StatusAccepted) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, response) + fmt.Fprint(w, response) }) } @@ -1471,7 +1471,7 @@ func HandleNodeGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestHeader(t, r, "Accept", "application/json") - fmt.Fprintf(w, SingleNodeBody) + fmt.Fprint(w, SingleNodeBody) }) } @@ -1483,7 +1483,7 @@ func HandleNodeUpdateSuccessfully(t *testing.T, response string) { th.TestHeader(t, r, "Content-Type", "application/json") th.TestJSONRequest(t, r, `[{"op": "replace", "path": "/properties", "value": {"root_gb": 25}}]`) - fmt.Fprintf(w, response) + fmt.Fprint(w, response) }) } @@ -1493,7 +1493,7 @@ func HandleNodeValidateSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestHeader(t, r, "Accept", "application/json") - fmt.Fprintf(w, NodeValidationBody) + fmt.Fprint(w, NodeValidationBody) }) } @@ -1525,7 +1525,7 @@ func HandleGetBootDeviceSuccessfully(t *testing.T) { th.TestMethod(t, r, "GET") th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, NodeBootDeviceBody) + fmt.Fprint(w, NodeBootDeviceBody) }) } @@ -1535,7 +1535,7 @@ func HandleGetSupportedBootDeviceSuccessfully(t *testing.T) { th.TestMethod(t, r, "GET") th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, NodeSupportedBootDeviceBody) + fmt.Fprint(w, NodeSupportedBootDeviceBody) }) } @@ -1667,7 +1667,7 @@ func HandleListBIOSSettingsSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestHeader(t, r, "Accept", "application/json") - fmt.Fprintf(w, NodeBIOSSettingsBody) + fmt.Fprint(w, NodeBIOSSettingsBody) }) } @@ -1677,7 +1677,7 @@ func HandleListDetailBIOSSettingsSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestHeader(t, r, "Accept", "application/json") - fmt.Fprintf(w, NodeDetailBIOSSettingsBody) + fmt.Fprint(w, NodeDetailBIOSSettingsBody) }) } @@ -1687,7 +1687,7 @@ func HandleGetBIOSSettingSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestHeader(t, r, "Accept", "application/json") - fmt.Fprintf(w, NodeSingleBIOSSettingBody) + fmt.Fprint(w, NodeSingleBIOSSettingBody) }) } @@ -1697,7 +1697,7 @@ func HandleGetVendorPassthruMethodsSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestHeader(t, r, "Accept", "application/json") - fmt.Fprintf(w, NodeVendorPassthruMethodsBody) + fmt.Fprint(w, NodeVendorPassthruMethodsBody) }) } @@ -1708,7 +1708,7 @@ func HandleGetAllSubscriptionsVendorPassthruSuccessfully(t *testing.T) { th.TestHeader(t, r, "Accept", "application/json") th.TestFormValues(t, r, map[string]string{"method": "get_all_subscriptions"}) - fmt.Fprintf(w, NodeGetAllSubscriptionsVnedorPassthruBody) + fmt.Fprint(w, NodeGetAllSubscriptionsVnedorPassthruBody) }) } @@ -1724,7 +1724,7 @@ func HandleGetSubscriptionVendorPassthruSuccessfully(t *testing.T) { } `) - fmt.Fprintf(w, NodeGetSubscriptionVendorPassthruBody) + fmt.Fprint(w, NodeGetSubscriptionVendorPassthruBody) }) } @@ -1744,7 +1744,7 @@ func HandleCreateSubscriptionVendorPassthruAllParametersSuccessfully(t *testing. } `) - fmt.Fprintf(w, NodeCreateSubscriptionVendorPassthruAllParametersBody) + fmt.Fprint(w, NodeCreateSubscriptionVendorPassthruAllParametersBody) }) } @@ -1760,7 +1760,7 @@ func HandleCreateSubscriptionVendorPassthruRequiredParametersSuccessfully(t *tes } `) - fmt.Fprintf(w, NodeCreateSubscriptionVendorPassthruRequiredParametersBody) + fmt.Fprint(w, NodeCreateSubscriptionVendorPassthruRequiredParametersBody) }) } @@ -1805,7 +1805,7 @@ func HandleGetInventorySuccessfully(t *testing.T) { th.TestMethod(t, r, "GET") th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, NodeInventoryBody) + fmt.Fprint(w, NodeInventoryBody) }) } @@ -1815,7 +1815,7 @@ func HandleListFirmwareSuccessfully(t *testing.T) { th.TestMethod(t, r, "GET") th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, NodeFirmwareListBody) + fmt.Fprint(w, NodeFirmwareListBody) }) } diff --git a/openstack/baremetal/v1/ports/testing/fixtures_test.go b/openstack/baremetal/v1/ports/testing/fixtures_test.go index 492aa42aa6..a6221ecd4a 100644 --- a/openstack/baremetal/v1/ports/testing/fixtures_test.go +++ b/openstack/baremetal/v1/ports/testing/fixtures_test.go @@ -181,10 +181,10 @@ func HandlePortListSuccessfully(t *testing.T) { marker := r.Form.Get("marker") switch marker { case "": - fmt.Fprintf(w, PortListBody) + fmt.Fprint(w, PortListBody) case "f2845e11-dbd4-4728-a8c0-30d19f48924a": - fmt.Fprintf(w, `{ "ports": [] }`) + fmt.Fprint(w, `{ "ports": [] }`) default: t.Fatalf("/ports invoked with unexpected marker=[%s]", marker) } @@ -201,7 +201,7 @@ func HandlePortListDetailSuccessfully(t *testing.T) { t.Errorf("Failed to parse request form %v", err) } - fmt.Fprintf(w, PortListDetailBody) + fmt.Fprint(w, PortListDetailBody) }) } @@ -219,7 +219,7 @@ func HandlePortCreationSuccessfully(t *testing.T, response string) { w.WriteHeader(http.StatusAccepted) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, response) + fmt.Fprint(w, response) }) } @@ -239,7 +239,7 @@ func HandlePortGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestHeader(t, r, "Accept", "application/json") - fmt.Fprintf(w, SinglePortBody) + fmt.Fprint(w, SinglePortBody) }) } @@ -251,6 +251,6 @@ func HandlePortUpdateSuccessfully(t *testing.T, response string) { th.TestHeader(t, r, "Content-Type", "application/json") th.TestJSONRequest(t, r, `[{"op": "replace", "path": "/address", "value": "22:22:22:22:22:22"}]`) - fmt.Fprintf(w, response) + fmt.Fprint(w, response) }) } diff --git a/openstack/baremetalintrospection/v1/introspection/testing/fixtures.go b/openstack/baremetalintrospection/v1/introspection/testing/fixtures.go index af2ad9e7f5..56a4299aef 100644 --- a/openstack/baremetalintrospection/v1/introspection/testing/fixtures.go +++ b/openstack/baremetalintrospection/v1/introspection/testing/fixtures.go @@ -467,10 +467,10 @@ func HandleListIntrospectionsSuccessfully(t *testing.T) { switch marker { case "": - fmt.Fprintf(w, IntrospectionListBody) + fmt.Fprint(w, IntrospectionListBody) case "c244557e-899f-46fa-a1ff-5b2c6718616b": - fmt.Fprintf(w, `{ "introspection": [] }`) + fmt.Fprint(w, `{ "introspection": [] }`) default: t.Fatalf("/introspection invoked with unexpected marker=[%s]", marker) @@ -484,7 +484,7 @@ func HandleGetIntrospectionStatusSuccessfully(t *testing.T) { th.TestMethod(t, r, "GET") th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestHeader(t, r, "Accept", "application/json") - fmt.Fprintf(w, IntrospectionStatus) + fmt.Fprint(w, IntrospectionStatus) }) } @@ -513,7 +513,7 @@ func HandleGetIntrospectionDataSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestHeader(t, r, "Accept", "application/json") - fmt.Fprintf(w, IntrospectionDataJSONSample) + fmt.Fprint(w, IntrospectionDataJSONSample) }) } diff --git a/openstack/blockstorage/apiversions/testing/fixtures_test.go b/openstack/blockstorage/apiversions/testing/fixtures_test.go index 4a368e9da9..ed78b1e472 100644 --- a/openstack/blockstorage/apiversions/testing/fixtures_test.go +++ b/openstack/blockstorage/apiversions/testing/fixtures_test.go @@ -124,7 +124,7 @@ func MockListResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, APIListResponse) + fmt.Fprint(w, APIListResponse) }) } @@ -136,6 +136,6 @@ func MockListOldResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, APIListOldResponse) + fmt.Fprint(w, APIListOldResponse) }) } diff --git a/openstack/blockstorage/v2/availabilityzones/testing/fixtures_test.go b/openstack/blockstorage/v2/availabilityzones/testing/fixtures_test.go index b13e464abb..5c48bdce2e 100644 --- a/openstack/blockstorage/v2/availabilityzones/testing/fixtures_test.go +++ b/openstack/blockstorage/v2/availabilityzones/testing/fixtures_test.go @@ -47,6 +47,6 @@ func HandleGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } diff --git a/openstack/blockstorage/v2/backups/testing/fixtures_test.go b/openstack/blockstorage/v2/backups/testing/fixtures_test.go index 2f24173418..4f1f45c122 100644 --- a/openstack/blockstorage/v2/backups/testing/fixtures_test.go +++ b/openstack/blockstorage/v2/backups/testing/fixtures_test.go @@ -210,7 +210,7 @@ func MockListResponse(t *testing.T) { case "": fmt.Fprintf(w, ListResponse, th.Server.URL) case "1": - fmt.Fprintf(w, `{"backups": []}`) + fmt.Fprint(w, `{"backups": []}`) default: t.Fatalf("Unexpected marker: [%s]", marker) } @@ -233,7 +233,7 @@ func MockListDetailResponse(t *testing.T) { case "": fmt.Fprintf(w, ListDetailResponse, th.Server.URL) case "1": - fmt.Fprintf(w, `{"backups": []}`) + fmt.Fprint(w, `{"backups": []}`) default: t.Fatalf("Unexpected marker: [%s]", marker) } @@ -247,7 +247,7 @@ func MockGetResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetResponse) + fmt.Fprint(w, GetResponse) }) } @@ -262,7 +262,7 @@ func MockCreateResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, CreateResponse) + fmt.Fprint(w, CreateResponse) }) } @@ -277,7 +277,7 @@ func MockRestoreResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, RestoreResponse) + fmt.Fprint(w, RestoreResponse) }) } @@ -298,7 +298,7 @@ func MockExportResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ExportResponse) + fmt.Fprint(w, ExportResponse) }) } @@ -313,7 +313,7 @@ func MockImportResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, ImportResponse) + fmt.Fprint(w, ImportResponse) }) } diff --git a/openstack/blockstorage/v2/limits/testing/fixtures_test.go b/openstack/blockstorage/v2/limits/testing/fixtures_test.go index c3f8bf803d..bdd1308a17 100644 --- a/openstack/blockstorage/v2/limits/testing/fixtures_test.go +++ b/openstack/blockstorage/v2/limits/testing/fixtures_test.go @@ -124,6 +124,6 @@ func HandleGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } diff --git a/openstack/blockstorage/v2/quotasets/testing/fixtures_test.go b/openstack/blockstorage/v2/quotasets/testing/fixtures_test.go index 066e1729c8..854ff08b63 100644 --- a/openstack/blockstorage/v2/quotasets/testing/fixtures_test.go +++ b/openstack/blockstorage/v2/quotasets/testing/fixtures_test.go @@ -164,7 +164,7 @@ func HandleSuccessfulRequest(t *testing.T, httpMethod, uriPath, jsonOutput strin th.TestFormValues(t, r, uriQueryParams) } - fmt.Fprintf(w, jsonOutput) + fmt.Fprint(w, jsonOutput) }) } diff --git a/openstack/blockstorage/v2/schedulerstats/testing/fixtures_test.go b/openstack/blockstorage/v2/schedulerstats/testing/fixtures_test.go index 3a7fee8160..05512dbf6d 100644 --- a/openstack/blockstorage/v2/schedulerstats/testing/fixtures_test.go +++ b/openstack/blockstorage/v2/schedulerstats/testing/fixtures_test.go @@ -104,9 +104,9 @@ func HandleStoragePoolsListSuccessfully(t *testing.T) { t.Errorf("Failed to parse request form %v", err) } if r.FormValue("detail") == "true" { - fmt.Fprintf(w, StoragePoolsListBodyDetail) + fmt.Fprint(w, StoragePoolsListBodyDetail) } else { - fmt.Fprintf(w, StoragePoolsListBody) + fmt.Fprint(w, StoragePoolsListBody) } }) } diff --git a/openstack/blockstorage/v2/services/testing/fixtures_test.go b/openstack/blockstorage/v2/services/testing/fixtures_test.go index a396abc39e..41fb5bc614 100644 --- a/openstack/blockstorage/v2/services/testing/fixtures_test.go +++ b/openstack/blockstorage/v2/services/testing/fixtures_test.go @@ -92,6 +92,6 @@ func HandleListSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, ServiceListBody) + fmt.Fprint(w, ServiceListBody) }) } diff --git a/openstack/blockstorage/v2/snapshots/testing/fixtures_test.go b/openstack/blockstorage/v2/snapshots/testing/fixtures_test.go index 2c00c8a05f..b2e5cf4c06 100644 --- a/openstack/blockstorage/v2/snapshots/testing/fixtures_test.go +++ b/openstack/blockstorage/v2/snapshots/testing/fixtures_test.go @@ -17,7 +17,7 @@ func MockListResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "snapshots": [ { @@ -51,7 +51,7 @@ func MockGetResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "snapshot": { "id": "d32019d3-bc6e-4319-9c1d-6722fc136a22", @@ -85,7 +85,7 @@ func MockCreateResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "snapshot": { "volume_id": "1234", @@ -115,7 +115,7 @@ func MockUpdateMetadataResponse(t *testing.T) { } `) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "metadata": { "key": "v1" diff --git a/openstack/blockstorage/v2/transfers/testing/fixtures_test.go b/openstack/blockstorage/v2/transfers/testing/fixtures_test.go index 6a150508eb..866d5068fc 100644 --- a/openstack/blockstorage/v2/transfers/testing/fixtures_test.go +++ b/openstack/blockstorage/v2/transfers/testing/fixtures_test.go @@ -167,7 +167,7 @@ func HandleCreateTransfer(t *testing.T) { th.TestJSONRequest(t, r, CreateRequest) w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, CreateResponse) + fmt.Fprint(w, CreateResponse) }) } @@ -179,7 +179,7 @@ func HandleAcceptTransfer(t *testing.T) { th.TestJSONRequest(t, r, AcceptTransferRequest) w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, AcceptTransferResponse) + fmt.Fprint(w, AcceptTransferResponse) }) } @@ -200,7 +200,7 @@ func HandleListTransfers(t *testing.T) { th.TestFormValues(t, r, map[string]string{"all_tenants": "true"}) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListOutput) + fmt.Fprint(w, ListOutput) }) } @@ -211,6 +211,6 @@ func HandleGetTransfer(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } diff --git a/openstack/blockstorage/v2/volumes/testing/fixtures_test.go b/openstack/blockstorage/v2/volumes/testing/fixtures_test.go index 80677d2e40..d6688f7850 100644 --- a/openstack/blockstorage/v2/volumes/testing/fixtures_test.go +++ b/openstack/blockstorage/v2/volumes/testing/fixtures_test.go @@ -17,7 +17,7 @@ func MockListResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "volumes": [ { @@ -93,7 +93,7 @@ func MockGetResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "volume": { "volume_type": "lvmdriver-1", @@ -152,7 +152,7 @@ func MockCreateResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "volume": { "size": 75, @@ -192,7 +192,7 @@ func MockUpdateResponse(t *testing.T) { th.TestMethod(t, r, "PUT") th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "volume": { "name": "vol-002" @@ -223,7 +223,7 @@ func MockAttachResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, `{}`) + fmt.Fprint(w, `{}`) }) } @@ -243,7 +243,7 @@ func MockBeginDetachingResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, `{}`) + fmt.Fprint(w, `{}`) }) } @@ -263,7 +263,7 @@ func MockDetachResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, `{}`) + fmt.Fprint(w, `{}`) }) } @@ -288,7 +288,7 @@ func MockUploadImageResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "os-volume_upload_image": { "container_format": "bare", @@ -335,7 +335,7 @@ func MockReserveResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, `{}`) + fmt.Fprint(w, `{}`) }) } @@ -355,7 +355,7 @@ func MockUnreserveResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, `{}`) + fmt.Fprint(w, `{}`) }) } @@ -386,7 +386,7 @@ func MockInitializeConnectionResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, `{ + fmt.Fprint(w, `{ "connection_info": { "data": { "target_portals": [ @@ -443,7 +443,7 @@ func MockTerminateConnectionResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, `{}`) + fmt.Fprint(w, `{}`) }) } @@ -466,7 +466,7 @@ func MockExtendSizeResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, `{}`) + fmt.Fprint(w, `{}`) }) } @@ -497,7 +497,7 @@ func MockSetImageMetadataResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, `{}`) + fmt.Fprint(w, `{}`) }) } @@ -560,7 +560,7 @@ func MockChangeTypeResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, `{}`) + fmt.Fprint(w, `{}`) }) } diff --git a/openstack/blockstorage/v3/attachments/testing/fixtures_test.go b/openstack/blockstorage/v3/attachments/testing/fixtures_test.go index d489ce16ef..18471c3b38 100644 --- a/openstack/blockstorage/v3/attachments/testing/fixtures_test.go +++ b/openstack/blockstorage/v3/attachments/testing/fixtures_test.go @@ -64,7 +64,7 @@ func MockListResponse(t *testing.T) { } `, th.Server.URL) case "1": - fmt.Fprintf(w, `{"volumes": []}`) + fmt.Fprint(w, `{"volumes": []}`) default: t.Fatalf("Unexpected marker: [%s]", marker) } @@ -78,7 +78,7 @@ func MockGetResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "attachment": { "status": "attaching", @@ -123,7 +123,7 @@ func MockCreateResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "attachment": { "status": "attaching", @@ -171,7 +171,7 @@ func MockUpdateResponse(t *testing.T) { `) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "attachment": { "status": "attaching", @@ -202,7 +202,7 @@ func MockUpdateEmptyResponse(t *testing.T) { `) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "attachment": { "status": "attaching", diff --git a/openstack/blockstorage/v3/availabilityzones/testing/fixtures_test.go b/openstack/blockstorage/v3/availabilityzones/testing/fixtures_test.go index 98f93db1d3..780c7dec26 100644 --- a/openstack/blockstorage/v3/availabilityzones/testing/fixtures_test.go +++ b/openstack/blockstorage/v3/availabilityzones/testing/fixtures_test.go @@ -47,6 +47,6 @@ func HandleGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } diff --git a/openstack/blockstorage/v3/backups/testing/fixtures_test.go b/openstack/blockstorage/v3/backups/testing/fixtures_test.go index 13fc1d61d9..9bbaec87d4 100644 --- a/openstack/blockstorage/v3/backups/testing/fixtures_test.go +++ b/openstack/blockstorage/v3/backups/testing/fixtures_test.go @@ -210,7 +210,7 @@ func MockListResponse(t *testing.T) { case "": fmt.Fprintf(w, ListResponse, th.Server.URL) case "1": - fmt.Fprintf(w, `{"backups": []}`) + fmt.Fprint(w, `{"backups": []}`) default: t.Fatalf("Unexpected marker: [%s]", marker) } @@ -233,7 +233,7 @@ func MockListDetailResponse(t *testing.T) { case "": fmt.Fprintf(w, ListDetailResponse, th.Server.URL) case "1": - fmt.Fprintf(w, `{"backups": []}`) + fmt.Fprint(w, `{"backups": []}`) default: t.Fatalf("Unexpected marker: [%s]", marker) } @@ -247,7 +247,7 @@ func MockGetResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetResponse) + fmt.Fprint(w, GetResponse) }) } @@ -262,7 +262,7 @@ func MockCreateResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, CreateResponse) + fmt.Fprint(w, CreateResponse) }) } @@ -277,7 +277,7 @@ func MockRestoreResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, RestoreResponse) + fmt.Fprint(w, RestoreResponse) }) } @@ -298,7 +298,7 @@ func MockExportResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ExportResponse) + fmt.Fprint(w, ExportResponse) }) } @@ -313,7 +313,7 @@ func MockImportResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, ImportResponse) + fmt.Fprint(w, ImportResponse) }) } diff --git a/openstack/blockstorage/v3/limits/testing/fixtures_test.go b/openstack/blockstorage/v3/limits/testing/fixtures_test.go index 5d3b647427..68fe8ae833 100644 --- a/openstack/blockstorage/v3/limits/testing/fixtures_test.go +++ b/openstack/blockstorage/v3/limits/testing/fixtures_test.go @@ -124,6 +124,6 @@ func HandleGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } diff --git a/openstack/blockstorage/v3/qos/testing/fixtures_test.go b/openstack/blockstorage/v3/qos/testing/fixtures_test.go index 8f9d2e2d51..e6cd002cea 100644 --- a/openstack/blockstorage/v3/qos/testing/fixtures_test.go +++ b/openstack/blockstorage/v3/qos/testing/fixtures_test.go @@ -47,7 +47,7 @@ func MockCreateResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "qos_specs": { "id": "d32019d3-bc6e-4319-9c1d-6722fc136a22", @@ -110,7 +110,7 @@ func MockListResponse(t *testing.T) { } `, th.Server.URL) case "2": - fmt.Fprintf(w, `{ "qos_specs": [] }`) + fmt.Fprint(w, `{ "qos_specs": [] }`) default: t.Fatalf("Unexpected marker: [%s]", marker) } @@ -124,7 +124,7 @@ func MockGetResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "qos_specs": { "id": "d32019d3-bc6e-4319-9c1d-6722fc136a22", @@ -172,7 +172,7 @@ func MockUpdateResponse(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdateBody) + fmt.Fprint(w, UpdateBody) }) } @@ -219,7 +219,7 @@ func MockListAssociationsResponse(t *testing.T) { th.TestMethod(t, r, "GET") th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "qos_associations": [ { diff --git a/openstack/blockstorage/v3/quotasets/testing/fixtures_test.go b/openstack/blockstorage/v3/quotasets/testing/fixtures_test.go index df029ff8e1..103afef6ef 100644 --- a/openstack/blockstorage/v3/quotasets/testing/fixtures_test.go +++ b/openstack/blockstorage/v3/quotasets/testing/fixtures_test.go @@ -164,7 +164,7 @@ func HandleSuccessfulRequest(t *testing.T, httpMethod, uriPath, jsonOutput strin th.TestFormValues(t, r, uriQueryParams) } - fmt.Fprintf(w, jsonOutput) + fmt.Fprint(w, jsonOutput) }) } diff --git a/openstack/blockstorage/v3/schedulerstats/testing/fixtures_test.go b/openstack/blockstorage/v3/schedulerstats/testing/fixtures_test.go index 0a1286e862..18462bfb20 100644 --- a/openstack/blockstorage/v3/schedulerstats/testing/fixtures_test.go +++ b/openstack/blockstorage/v3/schedulerstats/testing/fixtures_test.go @@ -104,9 +104,9 @@ func HandleStoragePoolsListSuccessfully(t *testing.T) { t.Errorf("Failed to parse request form %v", err) } if r.FormValue("detail") == "true" { - fmt.Fprintf(w, StoragePoolsListBodyDetail) + fmt.Fprint(w, StoragePoolsListBodyDetail) } else { - fmt.Fprintf(w, StoragePoolsListBody) + fmt.Fprint(w, StoragePoolsListBody) } }) } diff --git a/openstack/blockstorage/v3/services/testing/fixtures_test.go b/openstack/blockstorage/v3/services/testing/fixtures_test.go index adf7993df7..63771ff032 100644 --- a/openstack/blockstorage/v3/services/testing/fixtures_test.go +++ b/openstack/blockstorage/v3/services/testing/fixtures_test.go @@ -92,6 +92,6 @@ func HandleListSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, ServiceListBody) + fmt.Fprint(w, ServiceListBody) }) } diff --git a/openstack/blockstorage/v3/snapshots/testing/fixtures_test.go b/openstack/blockstorage/v3/snapshots/testing/fixtures_test.go index 8bbc45e77d..25e54b9b3e 100644 --- a/openstack/blockstorage/v3/snapshots/testing/fixtures_test.go +++ b/openstack/blockstorage/v3/snapshots/testing/fixtures_test.go @@ -54,7 +54,7 @@ func MockListResponse(t *testing.T) { } `, th.Server.URL) case "1": - fmt.Fprintf(w, `{"snapshots": []}`) + fmt.Fprint(w, `{"snapshots": []}`) default: t.Fatalf("Unexpected marker: [%s]", marker) } @@ -69,7 +69,7 @@ func MockGetResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "snapshot": { "id": "d32019d3-bc6e-4319-9c1d-6722fc136a22", @@ -104,7 +104,7 @@ func MockCreateResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "snapshot": { "volume_id": "1234", @@ -135,7 +135,7 @@ func MockUpdateMetadataResponse(t *testing.T) { } `) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "metadata": { "key": "v1" @@ -162,7 +162,7 @@ func MockUpdateResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "snapshot": { "id": "d32019d3-bc6e-4319-9c1d-6722fc136a22", diff --git a/openstack/blockstorage/v3/transfers/testing/fixtures_test.go b/openstack/blockstorage/v3/transfers/testing/fixtures_test.go index b2c11f60c7..859e454eca 100644 --- a/openstack/blockstorage/v3/transfers/testing/fixtures_test.go +++ b/openstack/blockstorage/v3/transfers/testing/fixtures_test.go @@ -167,7 +167,7 @@ func HandleCreateTransfer(t *testing.T) { th.TestJSONRequest(t, r, CreateRequest) w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, CreateResponse) + fmt.Fprint(w, CreateResponse) }) } @@ -179,7 +179,7 @@ func HandleAcceptTransfer(t *testing.T) { th.TestJSONRequest(t, r, AcceptTransferRequest) w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, AcceptTransferResponse) + fmt.Fprint(w, AcceptTransferResponse) }) } @@ -200,7 +200,7 @@ func HandleListTransfers(t *testing.T) { th.TestFormValues(t, r, map[string]string{"all_tenants": "true"}) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListOutput) + fmt.Fprint(w, ListOutput) }) } @@ -211,6 +211,6 @@ func HandleGetTransfer(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } diff --git a/openstack/blockstorage/v3/volumes/testing/fixtures_test.go b/openstack/blockstorage/v3/volumes/testing/fixtures_test.go index 4efb9e08f4..9b4630a978 100644 --- a/openstack/blockstorage/v3/volumes/testing/fixtures_test.go +++ b/openstack/blockstorage/v3/volumes/testing/fixtures_test.go @@ -95,7 +95,7 @@ func MockListResponse(t *testing.T) { } `, th.Server.URL) case "1": - fmt.Fprintf(w, `{"volumes": []}`) + fmt.Fprint(w, `{"volumes": []}`) default: t.Fatalf("Unexpected marker: [%s]", marker) } @@ -109,7 +109,7 @@ func MockGetResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "volume": { "volume_type": "lvmdriver-1", @@ -171,7 +171,7 @@ func MockCreateResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "volume": { "size": 75, @@ -211,7 +211,7 @@ func MockUpdateResponse(t *testing.T) { th.TestMethod(t, r, "PUT") th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "volume": { "name": "vol-002" @@ -239,7 +239,7 @@ func MockCreateVolumeFromBackupResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "volume": { "size": 30, @@ -287,7 +287,7 @@ func MockAttachResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, `{}`) + fmt.Fprint(w, `{}`) }) } @@ -307,7 +307,7 @@ func MockBeginDetachingResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, `{}`) + fmt.Fprint(w, `{}`) }) } @@ -327,7 +327,7 @@ func MockDetachResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, `{}`) + fmt.Fprint(w, `{}`) }) } @@ -352,7 +352,7 @@ func MockUploadImageResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "os-volume_upload_image": { "container_format": "bare", @@ -399,7 +399,7 @@ func MockReserveResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, `{}`) + fmt.Fprint(w, `{}`) }) } @@ -419,7 +419,7 @@ func MockUnreserveResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, `{}`) + fmt.Fprint(w, `{}`) }) } @@ -450,7 +450,7 @@ func MockInitializeConnectionResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, `{ + fmt.Fprint(w, `{ "connection_info": { "data": { "target_portals": [ @@ -507,7 +507,7 @@ func MockTerminateConnectionResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, `{}`) + fmt.Fprint(w, `{}`) }) } @@ -530,7 +530,7 @@ func MockExtendSizeResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, `{}`) + fmt.Fprint(w, `{}`) }) } @@ -561,7 +561,7 @@ func MockSetImageMetadataResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, `{}`) + fmt.Fprint(w, `{}`) }) } @@ -624,7 +624,7 @@ func MockChangeTypeResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, `{}`) + fmt.Fprint(w, `{}`) }) } diff --git a/openstack/blockstorage/v3/volumetypes/testing/fixtures_test.go b/openstack/blockstorage/v3/volumetypes/testing/fixtures_test.go index e1db5dfbd4..c7eb37893e 100644 --- a/openstack/blockstorage/v3/volumetypes/testing/fixtures_test.go +++ b/openstack/blockstorage/v3/volumetypes/testing/fixtures_test.go @@ -58,7 +58,7 @@ func MockListResponse(t *testing.T) { } `, th.Server.URL) case "1": - fmt.Fprintf(w, `{"volume_types": []}`) + fmt.Fprint(w, `{"volume_types": []}`) default: t.Fatalf("Unexpected marker: [%s]", marker) } @@ -72,7 +72,7 @@ func MockGetResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "volume_type": { "id": "d32019d3-bc6e-4319-9c1d-6722fc136a22", @@ -112,7 +112,7 @@ func MockCreateResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "volume_type": { "name": "test_type", @@ -143,7 +143,7 @@ func MockUpdateResponse(t *testing.T) { th.TestMethod(t, r, "PUT") th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "volume_type": { "name": "vol-type-002", @@ -203,7 +203,7 @@ func HandleExtraSpecsListSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ExtraSpecsGetBody) + fmt.Fprint(w, ExtraSpecsGetBody) }) } @@ -215,7 +215,7 @@ func HandleExtraSpecGetSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetExtraSpecBody) + fmt.Fprint(w, GetExtraSpecBody) }) } @@ -233,7 +233,7 @@ func HandleExtraSpecsCreateSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ExtraSpecsGetBody) + fmt.Fprint(w, ExtraSpecsGetBody) }) } @@ -248,7 +248,7 @@ func HandleExtraSpecUpdateSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdatedExtraSpecBody) + fmt.Fprint(w, UpdatedExtraSpecBody) }) } @@ -281,7 +281,7 @@ func MockEncryptionCreateResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "encryption": { "volume_type_id": "a5082c24-2a27-43a4-b48e-fcec1240e36b", @@ -324,7 +324,7 @@ func MockEncryptionUpdateResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "encryption": { "control_location": "front-end", @@ -345,7 +345,7 @@ func MockEncryptionGetResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "volume_type_id": "a5082c24-2a27-43a4-b48e-fcec1240e36b", "control_location": "front-end", @@ -370,7 +370,7 @@ func MockEncryptionGetSpecResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "cipher": "aes-xts-plain64" } diff --git a/openstack/blockstorage/v3/volumetypes/testing/requests_test.go b/openstack/blockstorage/v3/volumetypes/testing/requests_test.go index 56f22632f9..f222be2395 100644 --- a/openstack/blockstorage/v3/volumetypes/testing/requests_test.go +++ b/openstack/blockstorage/v3/volumetypes/testing/requests_test.go @@ -190,7 +190,7 @@ func TestVolumeTypeListAccesses(t *testing.T) { th.TestMethod(t, r, "GET") th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "volume_type_access": [ { diff --git a/openstack/common/extensions/testing/fixtures.go b/openstack/common/extensions/testing/fixtures.go index cfcdbe90e9..91f6a041b1 100644 --- a/openstack/common/extensions/testing/fixtures.go +++ b/openstack/common/extensions/testing/fixtures.go @@ -71,7 +71,7 @@ func HandleListExtensionsSuccessfully(t *testing.T) { w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, ListOutput) + fmt.Fprint(w, ListOutput) }) } @@ -85,6 +85,6 @@ func HandleGetExtensionSuccessfully(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } diff --git a/openstack/compute/apiversions/testing/fixtures_test.go b/openstack/compute/apiversions/testing/fixtures_test.go index c7f4b1a977..49162c77ce 100644 --- a/openstack/compute/apiversions/testing/fixtures_test.go +++ b/openstack/compute/apiversions/testing/fixtures_test.go @@ -169,7 +169,7 @@ func MockListResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, NovaAllAPIVersionsResponse) + fmt.Fprint(w, NovaAllAPIVersionsResponse) }) } @@ -181,7 +181,7 @@ func MockGetResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, NovaAPIVersionResponse_21) + fmt.Fprint(w, NovaAPIVersionResponse_21) }) } @@ -193,6 +193,6 @@ func MockGetMultipleResponses(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, NovaAPIInvalidVersionResponse) + fmt.Fprint(w, NovaAPIInvalidVersionResponse) }) } diff --git a/openstack/compute/v2/aggregates/testing/fixtures_test.go b/openstack/compute/v2/aggregates/testing/fixtures_test.go index a67678404f..11cebc8915 100644 --- a/openstack/compute/v2/aggregates/testing/fixtures_test.go +++ b/openstack/compute/v2/aggregates/testing/fixtures_test.go @@ -264,7 +264,7 @@ func HandleListSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, AggregateListBody) + fmt.Fprint(w, AggregateListBody) }) } @@ -274,7 +274,7 @@ func HandleCreateSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, AggregateCreateBody) + fmt.Fprint(w, AggregateCreateBody) }) } @@ -295,7 +295,7 @@ func HandleGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, AggregateGetBody) + fmt.Fprint(w, AggregateGetBody) }) } @@ -306,7 +306,7 @@ func HandleUpdateSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, AggregateUpdateBody) + fmt.Fprint(w, AggregateUpdateBody) }) } @@ -317,7 +317,7 @@ func HandleAddHostSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, AggregateAddHostBody) + fmt.Fprint(w, AggregateAddHostBody) }) } @@ -328,7 +328,7 @@ func HandleRemoveHostSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, AggregateRemoveHostBody) + fmt.Fprint(w, AggregateRemoveHostBody) }) } @@ -339,6 +339,6 @@ func HandleSetMetadataSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, AggregateSetMetadataBody) + fmt.Fprint(w, AggregateSetMetadataBody) }) } diff --git a/openstack/compute/v2/attachinterfaces/testing/fixtures_test.go b/openstack/compute/v2/attachinterfaces/testing/fixtures_test.go index 77bc48f55e..59a03d57d2 100644 --- a/openstack/compute/v2/attachinterfaces/testing/fixtures_test.go +++ b/openstack/compute/v2/attachinterfaces/testing/fixtures_test.go @@ -69,7 +69,7 @@ func HandleInterfaceListSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, `{ + fmt.Fprint(w, `{ "interfaceAttachments": [ { "port_state":"ACTIVE", @@ -99,7 +99,7 @@ func HandleInterfaceGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, `{ + fmt.Fprint(w, `{ "interfaceAttachment": { "port_state":"ACTIVE", @@ -133,7 +133,7 @@ func HandleInterfaceCreateSuccessfully(t *testing.T) { }`) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, `{ + fmt.Fprint(w, `{ "interfaceAttachment": { "port_state":"ACTIVE", diff --git a/openstack/compute/v2/availabilityzones/testing/fixtures_test.go b/openstack/compute/v2/availabilityzones/testing/fixtures_test.go index 059364bcc0..a36c64649c 100644 --- a/openstack/compute/v2/availabilityzones/testing/fixtures_test.go +++ b/openstack/compute/v2/availabilityzones/testing/fixtures_test.go @@ -180,7 +180,7 @@ func HandleGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } @@ -192,6 +192,6 @@ func HandleGetDetailSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, GetDetailOutput) + fmt.Fprint(w, GetDetailOutput) }) } diff --git a/openstack/compute/v2/extensions/testing/fixtures_test.go b/openstack/compute/v2/extensions/testing/fixtures_test.go index 6827dab20c..b1622af764 100644 --- a/openstack/compute/v2/extensions/testing/fixtures_test.go +++ b/openstack/compute/v2/extensions/testing/fixtures_test.go @@ -16,7 +16,7 @@ func HandleListExtensionsSuccessfully(t *testing.T) { w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "extensions": [ { @@ -41,7 +41,7 @@ func HandleGetExtensionsSuccessfully(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "extension": { "updated": "2013-02-03T10:00:00-00:00", diff --git a/openstack/compute/v2/flavors/testing/fixtures_test.go b/openstack/compute/v2/flavors/testing/fixtures_test.go index 94ac8c8a59..a92cdcd1d8 100644 --- a/openstack/compute/v2/flavors/testing/fixtures_test.go +++ b/openstack/compute/v2/flavors/testing/fixtures_test.go @@ -57,7 +57,7 @@ func HandleExtraSpecsListSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ExtraSpecsGetBody) + fmt.Fprint(w, ExtraSpecsGetBody) }) } @@ -69,7 +69,7 @@ func HandleExtraSpecGetSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetExtraSpecBody) + fmt.Fprint(w, GetExtraSpecBody) }) } @@ -87,7 +87,7 @@ func HandleExtraSpecsCreateSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ExtraSpecsGetBody) + fmt.Fprint(w, ExtraSpecsGetBody) }) } @@ -102,7 +102,7 @@ func HandleExtraSpecUpdateSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdatedExtraSpecBody) + fmt.Fprint(w, UpdatedExtraSpecBody) }) } diff --git a/openstack/compute/v2/flavors/testing/requests_test.go b/openstack/compute/v2/flavors/testing/requests_test.go index d22e3dfa9c..efd6e4bcee 100644 --- a/openstack/compute/v2/flavors/testing/requests_test.go +++ b/openstack/compute/v2/flavors/testing/requests_test.go @@ -76,7 +76,7 @@ func TestListFlavors(t *testing.T) { } `, th.Server.URL) case "2": - fmt.Fprintf(w, `{ "flavors": [] }`) + fmt.Fprint(w, `{ "flavors": [] }`) default: t.Fatalf("Unexpected marker: [%s]", marker) } @@ -121,7 +121,7 @@ func TestGetFlavor(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "flavor": { "id": "1", @@ -170,7 +170,7 @@ func TestCreateFlavor(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "flavor": { "id": "1", @@ -225,7 +225,7 @@ func TestUpdateFlavor(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "flavor": { "id": "1", @@ -288,7 +288,7 @@ func TestFlavorAccessesList(t *testing.T) { th.TestMethod(t, r, "GET") th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "flavor_access": [ { @@ -336,7 +336,7 @@ func TestFlavorAccessAdd(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "flavor_access": [ { @@ -385,7 +385,7 @@ func TestFlavorAccessRemove(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "flavor_access": [] } diff --git a/openstack/compute/v2/hypervisors/testing/fixtures_test.go b/openstack/compute/v2/hypervisors/testing/fixtures_test.go index 6e4b2e4aff..fa0b93a3f8 100644 --- a/openstack/compute/v2/hypervisors/testing/fixtures_test.go +++ b/openstack/compute/v2/hypervisors/testing/fixtures_test.go @@ -605,7 +605,7 @@ func HandleHypervisorsStatisticsSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, HypervisorsStatisticsBody) + fmt.Fprint(w, HypervisorsStatisticsBody) }) } @@ -615,7 +615,7 @@ func HandleHypervisorListPre253Successfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, HypervisorListBodyPre253) + fmt.Fprint(w, HypervisorListBodyPre253) }) } @@ -625,7 +625,7 @@ func HandleHypervisorListSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, HypervisorListBody) + fmt.Fprint(w, HypervisorListBody) }) } @@ -638,7 +638,7 @@ func HandleHypervisorListWithParametersSuccessfully(t *testing.T) { }) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, HypervisorListWithParametersBody) + fmt.Fprint(w, HypervisorListWithParametersBody) }) } @@ -648,7 +648,7 @@ func HandleHypervisorGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, HypervisorGetBody) + fmt.Fprint(w, HypervisorGetBody) }) } @@ -658,7 +658,7 @@ func HandleHypervisorGetEmptyCPUInfoSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, HypervisorGetEmptyCPUInfoBody) + fmt.Fprint(w, HypervisorGetEmptyCPUInfoBody) }) } @@ -668,7 +668,7 @@ func HandleHypervisorAfterV287ResponseSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, HypervisorAfterV287ResponseBody) + fmt.Fprint(w, HypervisorAfterV287ResponseBody) }) } @@ -678,6 +678,6 @@ func HandleHypervisorUptimeSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, HypervisorUptimeBody) + fmt.Fprint(w, HypervisorUptimeBody) }) } diff --git a/openstack/compute/v2/instanceactions/testing/fixtures_test.go b/openstack/compute/v2/instanceactions/testing/fixtures_test.go index 3b24801c38..cbbf6def28 100644 --- a/openstack/compute/v2/instanceactions/testing/fixtures_test.go +++ b/openstack/compute/v2/instanceactions/testing/fixtures_test.go @@ -40,7 +40,7 @@ func HandleInstanceActionListSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, `{ + fmt.Fprint(w, `{ "instanceActions": [ { "action": "stop", @@ -100,7 +100,7 @@ func HandleInstanceActionGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, `{ + fmt.Fprint(w, `{ "instanceAction": { "action": "stop", diff --git a/openstack/compute/v2/keypairs/testing/fixtures_test.go b/openstack/compute/v2/keypairs/testing/fixtures_test.go index 41532c03cc..92460e9259 100644 --- a/openstack/compute/v2/keypairs/testing/fixtures_test.go +++ b/openstack/compute/v2/keypairs/testing/fixtures_test.go @@ -157,7 +157,7 @@ func HandleListSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, ListOutput) + fmt.Fprint(w, ListOutput) }) } @@ -169,11 +169,11 @@ func HandleGetSuccessfully(t *testing.T) { if r.URL.Query().Get("user_id") == "fake2" { w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, GetOutputOtherUser) + fmt.Fprint(w, GetOutputOtherUser) } else { w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) } }) @@ -188,7 +188,7 @@ func HandleCreateSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, `{ "keypair": { "name": "createdkey" } }`) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, CreateOutput) + fmt.Fprint(w, CreateOutput) }) } @@ -201,7 +201,7 @@ func HandleCreateSuccessfullyOtherUser(t *testing.T) { th.TestJSONRequest(t, r, `{ "keypair": { "name": "createdkey", "user_id": "fake2" } }`) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, CreateOutputOtherUser) + fmt.Fprint(w, CreateOutputOtherUser) }) } @@ -221,7 +221,7 @@ func HandleImportSuccessfully(t *testing.T) { `) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, ImportOutput) + fmt.Fprint(w, ImportOutput) }) } diff --git a/openstack/compute/v2/limits/testing/fixtures_test.go b/openstack/compute/v2/limits/testing/fixtures_test.go index 3751c2d8b6..ee04c72442 100644 --- a/openstack/compute/v2/limits/testing/fixtures_test.go +++ b/openstack/compute/v2/limits/testing/fixtures_test.go @@ -75,6 +75,6 @@ func HandleGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } diff --git a/openstack/compute/v2/quotasets/testing/fixtures_test.go b/openstack/compute/v2/quotasets/testing/fixtures_test.go index d1c714714b..5d0ef24931 100644 --- a/openstack/compute/v2/quotasets/testing/fixtures_test.go +++ b/openstack/compute/v2/quotasets/testing/fixtures_test.go @@ -167,7 +167,7 @@ func HandleGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } @@ -177,7 +177,7 @@ func HandleGetDetailSuccessfully(t *testing.T) { th.TestMethod(t, r, "GET") th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, GetDetailsOutput) + fmt.Fprint(w, GetDetailsOutput) }) } @@ -188,7 +188,7 @@ func HandlePutSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestJSONRequest(t, r, UpdateOutput) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, UpdateOutput) + fmt.Fprint(w, UpdateOutput) }) } @@ -199,7 +199,7 @@ func HandlePartialPutSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestJSONRequest(t, r, PartialUpdateBody) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, UpdateOutput) + fmt.Fprint(w, UpdateOutput) }) } diff --git a/openstack/compute/v2/remoteconsoles/testing/requests_test.go b/openstack/compute/v2/remoteconsoles/testing/requests_test.go index e96b897d0f..3a49e4d46f 100644 --- a/openstack/compute/v2/remoteconsoles/testing/requests_test.go +++ b/openstack/compute/v2/remoteconsoles/testing/requests_test.go @@ -25,7 +25,7 @@ func TestCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, RemoteConsoleCreateResult) + fmt.Fprint(w, RemoteConsoleCreateResult) }) opts := remoteconsoles.CreateOpts{ diff --git a/openstack/compute/v2/secgroups/testing/fixtures_test.go b/openstack/compute/v2/secgroups/testing/fixtures_test.go index 0b35cc71d8..df3614b66b 100644 --- a/openstack/compute/v2/secgroups/testing/fixtures_test.go +++ b/openstack/compute/v2/secgroups/testing/fixtures_test.go @@ -33,7 +33,7 @@ func mockListGroupsResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, listGroupsJSON) + fmt.Fprint(w, listGroupsJSON) }) } @@ -46,7 +46,7 @@ func mockListGroupsByServerResponse(t *testing.T, serverID string) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, listGroupsJSON) + fmt.Fprint(w, listGroupsJSON) }) } @@ -67,7 +67,7 @@ func mockCreateGroupResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "security_group": { "description": "something", @@ -99,7 +99,7 @@ func mockUpdateGroupResponse(t *testing.T, groupID string) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "security_group": { "description": "something", @@ -122,7 +122,7 @@ func mockGetGroupsResponse(t *testing.T, groupID string) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "security_group": { "description": "default", @@ -224,7 +224,7 @@ func mockAddRuleResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "security_group_rule": { "from_port": 22, @@ -260,7 +260,7 @@ func mockAddRuleResponseICMPZero(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "security_group_rule": { "from_port": 0, diff --git a/openstack/compute/v2/servergroups/testing/fixtures_test.go b/openstack/compute/v2/servergroups/testing/fixtures_test.go index de36c3ff89..2ad519023a 100644 --- a/openstack/compute/v2/servergroups/testing/fixtures_test.go +++ b/openstack/compute/v2/servergroups/testing/fixtures_test.go @@ -148,7 +148,7 @@ func HandleListSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, ListOutput) + fmt.Fprint(w, ListOutput) }) } @@ -160,7 +160,7 @@ func HandleGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } @@ -172,7 +172,7 @@ func HandleGetMicroversionSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, GetOutputMicroversion) + fmt.Fprint(w, GetOutputMicroversion) }) } @@ -194,7 +194,7 @@ func HandleCreateSuccessfully(t *testing.T) { `) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, CreateOutput) + fmt.Fprint(w, CreateOutput) }) } @@ -220,7 +220,7 @@ func HandleCreateMicroversionSuccessfully(t *testing.T) { `) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, CreateOutputMicroversion) + fmt.Fprint(w, CreateOutputMicroversion) }) } diff --git a/openstack/compute/v2/servers/testing/fixtures_test.go b/openstack/compute/v2/servers/testing/fixtures_test.go index 2ce6282b02..1c25b40074 100644 --- a/openstack/compute/v2/servers/testing/fixtures_test.go +++ b/openstack/compute/v2/servers/testing/fixtures_test.go @@ -741,7 +741,7 @@ func HandleServerNoNetworkCreationSuccessfully(t *testing.T, response string) { w.WriteHeader(http.StatusAccepted) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, response) + fmt.Fprint(w, response) }) } @@ -761,7 +761,7 @@ func HandleServerCreationSuccessfully(t *testing.T, response string) { w.WriteHeader(http.StatusAccepted) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, response) + fmt.Fprint(w, response) }) th.Mux.HandleFunc("/images/detail", func(w http.ResponseWriter, r *http.Request) { @@ -775,7 +775,7 @@ func HandleServerCreationSuccessfully(t *testing.T, response string) { marker := r.Form.Get("marker") switch marker { case "": - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "images": [ { @@ -804,7 +804,7 @@ func HandleServerCreationSuccessfully(t *testing.T, response string) { } `) case "2": - fmt.Fprintf(w, `{ "images": [] }`) + fmt.Fprint(w, `{ "images": [] }`) default: t.Fatalf("Unexpected marker: [%s]", marker) } @@ -850,7 +850,7 @@ func HandleServerCreationSuccessfully(t *testing.T, response string) { } `, th.Server.URL) case "2": - fmt.Fprintf(w, `{ "flavors": [] }`) + fmt.Fprint(w, `{ "flavors": [] }`) default: t.Fatalf("Unexpected marker: [%s]", marker) } @@ -875,7 +875,7 @@ func HandleServersCreationSuccessfully(t *testing.T, response string) { w.WriteHeader(http.StatusAccepted) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, response) + fmt.Fprint(w, response) }) } @@ -896,7 +896,7 @@ func HandleServerCreationWithCustomFieldSuccessfully(t *testing.T, response stri w.WriteHeader(http.StatusAccepted) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, response) + fmt.Fprint(w, response) }) } @@ -915,7 +915,7 @@ func HandleServerCreationWithHostname(t *testing.T, response string) { w.WriteHeader(http.StatusAccepted) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, response) + fmt.Fprint(w, response) }) } @@ -936,7 +936,7 @@ func HandleServerCreationWithUserdata(t *testing.T, response string) { w.WriteHeader(http.StatusAccepted) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, response) + fmt.Fprint(w, response) }) } @@ -959,7 +959,7 @@ func HandleServerCreationWithMetadata(t *testing.T, response string) { w.WriteHeader(http.StatusAccepted) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, response) + fmt.Fprint(w, response) }) } @@ -976,9 +976,9 @@ func HandleServerListSimpleSuccessfully(t *testing.T) { marker := r.Form.Get("marker") switch marker { case "": - fmt.Fprintf(w, ServerListBody) + fmt.Fprint(w, ServerListBody) case "9e5476bd-a4ec-4653-93d6-72c93aa682ba": - fmt.Fprintf(w, `{ "servers": [] }`) + fmt.Fprint(w, `{ "servers": [] }`) default: t.Fatalf("/servers invoked with unexpected marker=[%s]", marker) } @@ -998,9 +998,9 @@ func HandleServerListSuccessfully(t *testing.T) { marker := r.Form.Get("marker") switch marker { case "": - fmt.Fprintf(w, ServerListBody) + fmt.Fprint(w, ServerListBody) case "9e5476bd-a4ec-4653-93d6-72c93aa682ba": - fmt.Fprintf(w, `{ "servers": [] }`) + fmt.Fprint(w, `{ "servers": [] }`) default: t.Fatalf("/servers/detail invoked with unexpected marker=[%s]", marker) } @@ -1036,7 +1036,7 @@ func HandleServerGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestHeader(t, r, "Accept", "application/json") - fmt.Fprintf(w, SingleServerBody) + fmt.Fprint(w, SingleServerBody) }) } @@ -1048,7 +1048,7 @@ func HandleServerGetFaultSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestHeader(t, r, "Accept", "application/json") - fmt.Fprintf(w, FaultyServerBody) + fmt.Fprint(w, FaultyServerBody) }) } @@ -1061,7 +1061,7 @@ func HandleServerUpdateSuccessfully(t *testing.T) { th.TestHeader(t, r, "Content-Type", "application/json") th.TestJSONRequest(t, r, `{ "server": { "name": "new-name" } }`) - fmt.Fprintf(w, SingleServerBody) + fmt.Fprint(w, SingleServerBody) }) } @@ -1097,7 +1097,7 @@ func HandleShowConsoleOutputSuccessfully(t *testing.T, response string) { w.WriteHeader(http.StatusOK) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, response) + fmt.Fprint(w, response) }) } @@ -1119,7 +1119,7 @@ func HandleRebuildSuccessfully(t *testing.T, response string) { w.WriteHeader(http.StatusAccepted) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, response) + fmt.Fprint(w, response) }) } @@ -1243,7 +1243,7 @@ func HandleAddressListSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, `{ + fmt.Fprint(w, `{ "addresses": { "public": [ { @@ -1285,7 +1285,7 @@ func HandleNetworkAddressListSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, `{ + fmt.Fprint(w, `{ "public": [ { "version": 4, @@ -1317,7 +1317,7 @@ func HandlePasswordGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestHeader(t, r, "Accept", "application/json") - fmt.Fprintf(w, ServerPasswordBody) + fmt.Fprint(w, ServerPasswordBody) }) } @@ -1332,6 +1332,6 @@ func HandleServerWithTagsCreationSuccessfully(t *testing.T) { w.WriteHeader(http.StatusAccepted) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, SingleServerWithTagsBody) + fmt.Fprint(w, SingleServerWithTagsBody) }) } diff --git a/openstack/compute/v2/services/testing/fixtures_test.go b/openstack/compute/v2/services/testing/fixtures_test.go index 2104dc08cb..93b124df90 100644 --- a/openstack/compute/v2/services/testing/fixtures_test.go +++ b/openstack/compute/v2/services/testing/fixtures_test.go @@ -259,7 +259,7 @@ func HandleListPre253Successfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, ServiceListBodyPre253) + fmt.Fprint(w, ServiceListBodyPre253) }) } @@ -271,7 +271,7 @@ func HandleListSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, ServiceListBody) + fmt.Fprint(w, ServiceListBody) }) } @@ -285,7 +285,7 @@ func HandleUpdateSuccessfully(t *testing.T) { th.TestHeader(t, r, "Content-Type", "application/json") th.TestJSONRequest(t, r, `{"status": "disabled"}`) - fmt.Fprintf(w, ServiceUpdate) + fmt.Fprint(w, ServiceUpdate) }) } diff --git a/openstack/compute/v2/tags/testing/requests_test.go b/openstack/compute/v2/tags/testing/requests_test.go index 03f4260a7d..dc524a2306 100644 --- a/openstack/compute/v2/tags/testing/requests_test.go +++ b/openstack/compute/v2/tags/testing/requests_test.go @@ -22,7 +22,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - _, err := fmt.Fprintf(w, TagsListResponse) + _, err := fmt.Fprint(w, TagsListResponse) th.AssertNoErr(t, err) }) @@ -78,7 +78,7 @@ func TestReplaceAll(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - _, err := fmt.Fprintf(w, TagsReplaceAllResponse) + _, err := fmt.Fprint(w, TagsReplaceAllResponse) th.AssertNoErr(t, err) }) diff --git a/openstack/compute/v2/volumeattach/testing/fixtures_test.go b/openstack/compute/v2/volumeattach/testing/fixtures_test.go index c5f0435a96..d9ada1e8c1 100644 --- a/openstack/compute/v2/volumeattach/testing/fixtures_test.go +++ b/openstack/compute/v2/volumeattach/testing/fixtures_test.go @@ -62,7 +62,7 @@ func HandleListSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, ListOutput) + fmt.Fprint(w, ListOutput) }) } @@ -74,7 +74,7 @@ func HandleGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } @@ -96,7 +96,7 @@ func HandleCreateSuccessfully(t *testing.T) { `) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, CreateOutput) + fmt.Fprint(w, CreateOutput) }) } diff --git a/openstack/container/v1/capsules/testing/fixtures_test.go b/openstack/container/v1/capsules/testing/fixtures_test.go index fe7b008013..779a41a0df 100644 --- a/openstack/container/v1/capsules/testing/fixtures_test.go +++ b/openstack/container/v1/capsules/testing/fixtures_test.go @@ -609,7 +609,7 @@ func HandleCapsuleGetOldTimeSuccessfully(t *testing.T) { w.WriteHeader(http.StatusOK) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, CapsuleGetBody_OldTime) + fmt.Fprint(w, CapsuleGetBody_OldTime) }) } @@ -621,7 +621,7 @@ func HandleCapsuleGetNewTimeSuccessfully(t *testing.T) { w.WriteHeader(http.StatusOK) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, CapsuleGetBody_NewTime) + fmt.Fprint(w, CapsuleGetBody_NewTime) }) } @@ -633,7 +633,7 @@ func HandleCapsuleCreateSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", fakeclient.TokenID) th.TestHeader(t, r, "Accept", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, CapsuleGetBody_NewTime) + fmt.Fprint(w, CapsuleGetBody_NewTime) }) } @@ -645,7 +645,7 @@ func HandleCapsuleListSuccessfully(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, CapsuleListBody) + fmt.Fprint(w, CapsuleListBody) }) } @@ -657,7 +657,7 @@ func HandleCapsuleV132ListSuccessfully(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, CapsuleV132ListBody) + fmt.Fprint(w, CapsuleV132ListBody) }) } diff --git a/openstack/containerinfra/apiversions/testing/fixtures_test.go b/openstack/containerinfra/apiversions/testing/fixtures_test.go index e95058151d..f42844214c 100644 --- a/openstack/containerinfra/apiversions/testing/fixtures_test.go +++ b/openstack/containerinfra/apiversions/testing/fixtures_test.go @@ -71,7 +71,7 @@ func MockListResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, MagnumAllAPIVersionsResponse) + fmt.Fprint(w, MagnumAllAPIVersionsResponse) }) } @@ -83,6 +83,6 @@ func MockGetResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, MagnumAPIVersionResponse) + fmt.Fprint(w, MagnumAPIVersionResponse) }) } diff --git a/openstack/containerinfra/v1/certificates/testing/fixtures_test.go b/openstack/containerinfra/v1/certificates/testing/fixtures_test.go index 3f88c34242..b51d77cbd4 100644 --- a/openstack/containerinfra/v1/certificates/testing/fixtures_test.go +++ b/openstack/containerinfra/v1/certificates/testing/fixtures_test.go @@ -106,6 +106,6 @@ func HandleUpdateCertificateSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, `{}`) + fmt.Fprint(w, `{}`) }) } diff --git a/openstack/containerinfra/v1/nodegroups/testing/fixtures_test.go b/openstack/containerinfra/v1/nodegroups/testing/fixtures_test.go index 51e63cc318..90de8b6fe6 100644 --- a/openstack/containerinfra/v1/nodegroups/testing/fixtures_test.go +++ b/openstack/containerinfra/v1/nodegroups/testing/fixtures_test.go @@ -221,7 +221,7 @@ func handleCreateNodeGroupSuccess(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, nodeGroupCreateResponse) + fmt.Fprint(w, nodeGroupCreateResponse) }) } @@ -233,7 +233,7 @@ func handleCreateNodeGroupDuplicate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusConflict) - fmt.Fprintf(w, nodeGroupCreateDuplicateResponse) + fmt.Fprint(w, nodeGroupCreateDuplicateResponse) }) } @@ -245,7 +245,7 @@ func handleCreateNodeGroupMaster(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusBadRequest) - fmt.Fprintf(w, nodeGroupCreateMasterResponse) + fmt.Fprint(w, nodeGroupCreateMasterResponse) }) } @@ -257,7 +257,7 @@ func handleCreateNodeGroupBadSizes(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusConflict) - fmt.Fprintf(w, nodeGroupCreateBadSizesResponse) + fmt.Fprint(w, nodeGroupCreateBadSizesResponse) }) } @@ -269,7 +269,7 @@ func handleUpdateNodeGroupSuccess(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, nodeGroupUpdateResponse) + fmt.Fprint(w, nodeGroupUpdateResponse) }) } @@ -281,7 +281,7 @@ func handleUpdateNodeGroupInternal(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusBadRequest) - fmt.Fprintf(w, nodeGroupUpdateInternalResponse) + fmt.Fprint(w, nodeGroupUpdateInternalResponse) }) } @@ -293,7 +293,7 @@ func handleUpdateNodeGroupBadField(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusBadRequest) - fmt.Fprintf(w, nodeGroupUpdateBadFieldResponse) + fmt.Fprint(w, nodeGroupUpdateBadFieldResponse) }) } @@ -305,7 +305,7 @@ func handleUpdateNodeGroupBadMin(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusConflict) - fmt.Fprintf(w, nodeGroupUpdateBadMinResponse) + fmt.Fprint(w, nodeGroupUpdateBadMinResponse) }) } @@ -326,7 +326,7 @@ func handleDeleteNodeGroupNotFound(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusNotFound) - fmt.Fprintf(w, nodeGroupDeleteNotFoundResponse) + fmt.Fprint(w, nodeGroupDeleteNotFoundResponse) }) } @@ -338,7 +338,7 @@ func handleDeleteNodeGroupClusterNotFound(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusNotFound) - fmt.Fprintf(w, nodeGroupDeleteClusterNotFoundResponse) + fmt.Fprint(w, nodeGroupDeleteClusterNotFoundResponse) }) } @@ -350,7 +350,7 @@ func handleDeleteNodeGroupDefault(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusBadRequest) - fmt.Fprintf(w, nodeGroupDeleteDefaultResponse) + fmt.Fprint(w, nodeGroupDeleteDefaultResponse) }) } diff --git a/openstack/dns/v2/recordsets/testing/fixtures_test.go b/openstack/dns/v2/recordsets/testing/fixtures_test.go index 9d2289f100..71d1d0898e 100644 --- a/openstack/dns/v2/recordsets/testing/fixtures_test.go +++ b/openstack/dns/v2/recordsets/testing/fixtures_test.go @@ -212,9 +212,9 @@ func HandleListByZoneSuccessfully(t *testing.T) { marker := r.Form.Get("marker") switch marker { case "f7b10e9b-0cae-4a91-b162-562bc6096648": - fmt.Fprintf(w, ListByZoneOutputLimited) + fmt.Fprint(w, ListByZoneOutputLimited) case "": - fmt.Fprintf(w, ListByZoneOutput) + fmt.Fprint(w, ListByZoneOutput) } }) } @@ -227,7 +227,7 @@ func HandleGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } @@ -282,7 +282,7 @@ func HandleCreateSuccessfully(t *testing.T) { w.WriteHeader(http.StatusCreated) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, CreateRecordSetResponse) + fmt.Fprint(w, CreateRecordSetResponse) }) } @@ -334,7 +334,7 @@ func HandleUpdateSuccessfully(t *testing.T) { w.WriteHeader(http.StatusOK) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, UpdateRecordSetResponse) + fmt.Fprint(w, UpdateRecordSetResponse) }) } @@ -373,6 +373,6 @@ func HandleDeleteSuccessfully(t *testing.T) { w.WriteHeader(http.StatusAccepted) //w.Header().Add("Content-Type", "application/json") - //fmt.Fprintf(w, DeleteZoneResponse) + //fmt.Fprint(w, DeleteZoneResponse) }) } diff --git a/openstack/dns/v2/transfer/accept/testing/fixtures_test.go b/openstack/dns/v2/transfer/accept/testing/fixtures_test.go index b8c3fe5888..3dae54e6aa 100644 --- a/openstack/dns/v2/transfer/accept/testing/fixtures_test.go +++ b/openstack/dns/v2/transfer/accept/testing/fixtures_test.go @@ -133,7 +133,7 @@ func HandleListSuccessfully(t *testing.T) { th.TestMethod(t, r, "GET") th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, ListOutput) + fmt.Fprint(w, ListOutput) }) } @@ -145,7 +145,7 @@ func HandleFilteredListSuccessfully(t *testing.T) { th.TestMethod(t, r, "GET") th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, FilteredListOutput) + fmt.Fprint(w, FilteredListOutput) }) } @@ -157,7 +157,7 @@ func HandleGetSuccessfully(t *testing.T) { th.TestMethod(t, r, "GET") th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } @@ -200,6 +200,6 @@ func HandleCreateSuccessfully(t *testing.T) { w.WriteHeader(http.StatusCreated) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, CreateTransferAcceptResponse) + fmt.Fprint(w, CreateTransferAcceptResponse) }) } diff --git a/openstack/dns/v2/transfer/request/testing/fixtures_test.go b/openstack/dns/v2/transfer/request/testing/fixtures_test.go index 758b566604..3de1f2aca3 100644 --- a/openstack/dns/v2/transfer/request/testing/fixtures_test.go +++ b/openstack/dns/v2/transfer/request/testing/fixtures_test.go @@ -119,7 +119,7 @@ func HandleListSuccessfully(t *testing.T) { th.TestMethod(t, r, "GET") th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, ListOutput) + fmt.Fprint(w, ListOutput) }) } @@ -131,7 +131,7 @@ func HandleGetSuccessfully(t *testing.T) { th.TestMethod(t, r, "GET") th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } @@ -175,7 +175,7 @@ func HandleCreateSuccessfully(t *testing.T) { w.WriteHeader(http.StatusCreated) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, CreateTransferRequestResponse) + fmt.Fprint(w, CreateTransferRequestResponse) }) } @@ -215,7 +215,7 @@ func HandleUpdateSuccessfully(t *testing.T) { w.WriteHeader(http.StatusOK) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, UpdatedTransferRequestResponse) + fmt.Fprint(w, UpdatedTransferRequestResponse) }) } diff --git a/openstack/dns/v2/zones/testing/fixtures_test.go b/openstack/dns/v2/zones/testing/fixtures_test.go index d7d9120643..6b0ee7ccf7 100644 --- a/openstack/dns/v2/zones/testing/fixtures_test.go +++ b/openstack/dns/v2/zones/testing/fixtures_test.go @@ -149,7 +149,7 @@ func HandleListSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, ListOutput) + fmt.Fprint(w, ListOutput) }) } @@ -160,7 +160,7 @@ func HandleGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } @@ -212,7 +212,7 @@ func HandleCreateSuccessfully(t *testing.T) { w.WriteHeader(http.StatusCreated) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, CreateZoneResponse) + fmt.Fprint(w, CreateZoneResponse) }) } @@ -259,7 +259,7 @@ func HandleUpdateSuccessfully(t *testing.T) { w.WriteHeader(http.StatusOK) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, UpdateZoneResponse) + fmt.Fprint(w, UpdateZoneResponse) }) } @@ -297,6 +297,6 @@ func HandleDeleteSuccessfully(t *testing.T) { w.WriteHeader(http.StatusAccepted) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, DeleteZoneResponse) + fmt.Fprint(w, DeleteZoneResponse) }) } diff --git a/openstack/identity/v2/extensions/testing/fixtures_test.go b/openstack/identity/v2/extensions/testing/fixtures_test.go index 3733eba312..8e9bfa14da 100644 --- a/openstack/identity/v2/extensions/testing/fixtures_test.go +++ b/openstack/identity/v2/extensions/testing/fixtures_test.go @@ -37,7 +37,7 @@ func HandleListExtensionsSuccessfully(t *testing.T) { w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "extensions": { "values": [ diff --git a/openstack/identity/v2/roles/testing/fixtures_test.go b/openstack/identity/v2/roles/testing/fixtures_test.go index 0b5af6e541..170e80099c 100644 --- a/openstack/identity/v2/roles/testing/fixtures_test.go +++ b/openstack/identity/v2/roles/testing/fixtures_test.go @@ -17,7 +17,7 @@ func MockListRoleResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "roles": [ { diff --git a/openstack/identity/v2/tenants/testing/fixtures_test.go b/openstack/identity/v2/tenants/testing/fixtures_test.go index 7c50152faa..e7de74ccd5 100644 --- a/openstack/identity/v2/tenants/testing/fixtures_test.go +++ b/openstack/identity/v2/tenants/testing/fixtures_test.go @@ -59,7 +59,7 @@ func HandleListTenantsSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListOutput) + fmt.Fprint(w, ListOutput) }) } @@ -81,7 +81,7 @@ func mockCreateTenantResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "tenant": { "name": "new_tenant", @@ -120,7 +120,7 @@ func mockUpdateTenantResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "tenant": { "name": "new_name", @@ -141,7 +141,7 @@ func mockGetTenantResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "tenant": { "name": "new_tenant", diff --git a/openstack/identity/v2/tokens/testing/fixtures_test.go b/openstack/identity/v2/tokens/testing/fixtures_test.go index 8eb7d6f7ea..1ee6d32e75 100644 --- a/openstack/identity/v2/tokens/testing/fixtures_test.go +++ b/openstack/identity/v2/tokens/testing/fixtures_test.go @@ -152,7 +152,7 @@ func HandleTokenPost(t *testing.T, requestJSON string) { } w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, TokenCreationResponse) + fmt.Fprint(w, TokenCreationResponse) }) } @@ -165,7 +165,7 @@ func HandleTokenGet(t *testing.T, token string) { th.TestHeader(t, r, "X-Auth-Token", thclient.TokenID) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, TokenGetResponse) + fmt.Fprint(w, TokenGetResponse) }) } diff --git a/openstack/identity/v2/users/testing/fixtures_test.go b/openstack/identity/v2/users/testing/fixtures_test.go index f38f05dba2..3e5285360b 100644 --- a/openstack/identity/v2/users/testing/fixtures_test.go +++ b/openstack/identity/v2/users/testing/fixtures_test.go @@ -17,7 +17,7 @@ func MockListUserResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "users":[ { @@ -61,7 +61,7 @@ func mockCreateUserResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "user": { "name": "new_user", @@ -83,7 +83,7 @@ func mockGetUserResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "user": { "name": "new_user", @@ -115,7 +115,7 @@ func mockUpdateUserResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "user": { "name": "new_name", @@ -145,7 +145,7 @@ func mockListRolesResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "roles": [ { diff --git a/openstack/identity/v3/applicationcredentials/testing/fixtures_test.go b/openstack/identity/v3/applicationcredentials/testing/fixtures_test.go index fabb021a0c..ae06c1bc57 100644 --- a/openstack/identity/v3/applicationcredentials/testing/fixtures_test.go +++ b/openstack/identity/v3/applicationcredentials/testing/fixtures_test.go @@ -415,7 +415,7 @@ func HandleListApplicationCredentialsSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListOutput) + fmt.Fprint(w, ListOutput) }) } @@ -429,7 +429,7 @@ func HandleGetApplicationCredentialSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } @@ -442,7 +442,7 @@ func HandleCreateApplicationCredentialSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, CreateRequest) w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreateResponse) + fmt.Fprint(w, CreateResponse) }) } @@ -455,7 +455,7 @@ func HandleCreateNoSecretApplicationCredentialSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, CreateNoSecretRequest) w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreateNoSecretResponse) + fmt.Fprint(w, CreateNoSecretResponse) }) } @@ -466,7 +466,7 @@ func HandleCreateUnrestrictedApplicationCredentialSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, CreateUnrestrictedRequest) w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreateUnrestrictedResponse) + fmt.Fprint(w, CreateUnrestrictedResponse) }) } @@ -491,7 +491,7 @@ func HandleListAccessRulesSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListAccessRulesOutput) + fmt.Fprint(w, ListAccessRulesOutput) }) } @@ -505,7 +505,7 @@ func HandleGetAccessRuleSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetAccessRuleOutput) + fmt.Fprint(w, GetAccessRuleOutput) }) } diff --git a/openstack/identity/v3/catalog/testing/fixtures_test.go b/openstack/identity/v3/catalog/testing/fixtures_test.go index 541fcac4af..ad9e9d9ce2 100644 --- a/openstack/identity/v3/catalog/testing/fixtures_test.go +++ b/openstack/identity/v3/catalog/testing/fixtures_test.go @@ -85,6 +85,6 @@ func HandleListCatalogSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - _, _ = fmt.Fprintf(w, ListOutput) + _, _ = fmt.Fprint(w, ListOutput) }) } diff --git a/openstack/identity/v3/credentials/testing/fixtures_test.go b/openstack/identity/v3/credentials/testing/fixtures_test.go index 8da4769ed6..e32d77d0db 100644 --- a/openstack/identity/v3/credentials/testing/fixtures_test.go +++ b/openstack/identity/v3/credentials/testing/fixtures_test.go @@ -161,7 +161,7 @@ func HandleListCredentialsSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListOutput) + fmt.Fprint(w, ListOutput) }) } @@ -175,7 +175,7 @@ func HandleGetCredentialSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } @@ -188,7 +188,7 @@ func HandleCreateCredentialSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, CreateRequest) w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } @@ -212,6 +212,6 @@ func HandleUpdateCredentialSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, UpdateRequest) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdateOutput) + fmt.Fprint(w, UpdateOutput) }) } diff --git a/openstack/identity/v3/domains/testing/fixtures_test.go b/openstack/identity/v3/domains/testing/fixtures_test.go index f5025a15c8..a35813a23c 100644 --- a/openstack/identity/v3/domains/testing/fixtures_test.go +++ b/openstack/identity/v3/domains/testing/fixtures_test.go @@ -189,7 +189,7 @@ func HandleListAvailableDomainsSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListAvailableOutput) + fmt.Fprint(w, ListAvailableOutput) }) } @@ -203,7 +203,7 @@ func HandleListDomainsSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListOutput) + fmt.Fprint(w, ListOutput) }) } @@ -217,7 +217,7 @@ func HandleGetDomainSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } @@ -230,7 +230,7 @@ func HandleCreateDomainSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, CreateRequest) w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } @@ -254,6 +254,6 @@ func HandleUpdateDomainSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, UpdateRequest) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdateOutput) + fmt.Fprint(w, UpdateOutput) }) } diff --git a/openstack/identity/v3/ec2credentials/testing/fixtures_test.go b/openstack/identity/v3/ec2credentials/testing/fixtures_test.go index 738161477d..72a82e1ff4 100644 --- a/openstack/identity/v3/ec2credentials/testing/fixtures_test.go +++ b/openstack/identity/v3/ec2credentials/testing/fixtures_test.go @@ -119,7 +119,7 @@ func HandleListEC2CredentialsSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListOutput) + fmt.Fprint(w, ListOutput) }) } @@ -133,7 +133,7 @@ func HandleGetEC2CredentialSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } @@ -146,7 +146,7 @@ func HandleCreateEC2CredentialSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, CreateRequest) w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreateResponse) + fmt.Fprint(w, CreateResponse) }) } diff --git a/openstack/identity/v3/ec2tokens/testing/requests_test.go b/openstack/identity/v3/ec2tokens/testing/requests_test.go index 13239e2d91..8fe0b3c3f8 100644 --- a/openstack/identity/v3/ec2tokens/testing/requests_test.go +++ b/openstack/identity/v3/ec2tokens/testing/requests_test.go @@ -32,7 +32,7 @@ func authTokenPost(t *testing.T, options ec2tokens.AuthOptions, requestJSON stri th.TestJSONRequest(t, r, requestJSON) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, tokens_testing.TokenOutput) + fmt.Fprint(w, tokens_testing.TokenOutput) }) expected := &tokens.Token{ diff --git a/openstack/identity/v3/endpoints/testing/requests_test.go b/openstack/identity/v3/endpoints/testing/requests_test.go index 8ea857bad4..348a1f1c6e 100644 --- a/openstack/identity/v3/endpoints/testing/requests_test.go +++ b/openstack/identity/v3/endpoints/testing/requests_test.go @@ -33,7 +33,7 @@ func TestCreateSuccessful(t *testing.T) { `) w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "endpoint": { "id": "12", @@ -82,7 +82,7 @@ func TestListEndpoints(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "endpoints": [ { @@ -170,7 +170,7 @@ func TestUpdateEndpoint(t *testing.T) { } `) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "endpoint": { "id": "12", diff --git a/openstack/identity/v3/federation/testing/fixtures_test.go b/openstack/identity/v3/federation/testing/fixtures_test.go index 225cc57997..229d2f489a 100644 --- a/openstack/identity/v3/federation/testing/fixtures_test.go +++ b/openstack/identity/v3/federation/testing/fixtures_test.go @@ -289,7 +289,7 @@ func HandleListMappingsSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListOutput) + fmt.Fprint(w, ListOutput) }) } @@ -302,7 +302,7 @@ func HandleCreateMappingSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, CreateRequest) w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreateOutput) + fmt.Fprint(w, CreateOutput) }) } @@ -316,7 +316,7 @@ func HandleGetMappingSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } @@ -329,7 +329,7 @@ func HandleUpdateMappingSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, UpdateRequest) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdateOutput) + fmt.Fprint(w, UpdateOutput) }) } diff --git a/openstack/identity/v3/groups/testing/fixtures_test.go b/openstack/identity/v3/groups/testing/fixtures_test.go index 0357a1fe06..415d81555f 100644 --- a/openstack/identity/v3/groups/testing/fixtures_test.go +++ b/openstack/identity/v3/groups/testing/fixtures_test.go @@ -160,7 +160,7 @@ func HandleListGroupsSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListOutput) + fmt.Fprint(w, ListOutput) }) } @@ -174,7 +174,7 @@ func HandleGetGroupSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } @@ -187,7 +187,7 @@ func HandleCreateGroupSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, CreateRequest) w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } @@ -200,7 +200,7 @@ func HandleUpdateGroupSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, UpdateRequest) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdateOutput) + fmt.Fprint(w, UpdateOutput) }) } diff --git a/openstack/identity/v3/limits/testing/fixtures_test.go b/openstack/identity/v3/limits/testing/fixtures_test.go index 6275235b54..5f8cbff160 100644 --- a/openstack/identity/v3/limits/testing/fixtures_test.go +++ b/openstack/identity/v3/limits/testing/fixtures_test.go @@ -183,7 +183,7 @@ func HandleGetEnforcementModelSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetEnforcementModelOutput) + fmt.Fprint(w, GetEnforcementModelOutput) }) } @@ -197,7 +197,7 @@ func HandleListLimitsSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListOutput) + fmt.Fprint(w, ListOutput) }) } @@ -210,7 +210,7 @@ func HandleCreateLimitSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, CreateRequest) w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreateOutput) + fmt.Fprint(w, CreateOutput) }) } @@ -224,7 +224,7 @@ func HandleGetLimitSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } @@ -237,7 +237,7 @@ func HandleUpdateLimitSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, UpdateRequest) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdateOutput) + fmt.Fprint(w, UpdateOutput) }) } diff --git a/openstack/identity/v3/oauth1/testing/fixtures_test.go b/openstack/identity/v3/oauth1/testing/fixtures_test.go index 3e8d144047..b8d5dc3327 100644 --- a/openstack/identity/v3/oauth1/testing/fixtures_test.go +++ b/openstack/identity/v3/oauth1/testing/fixtures_test.go @@ -228,7 +228,7 @@ func HandleCreateConsumer(t *testing.T) { th.TestJSONRequest(t, r, CreateConsumerRequest) w.WriteHeader(http.StatusCreated) - _, err := fmt.Fprintf(w, CreateConsumerResponse) + _, err := fmt.Fprint(w, CreateConsumerResponse) th.AssertNoErr(t, err) }) } @@ -243,7 +243,7 @@ func HandleUpdateConsumer(t *testing.T) { th.TestJSONRequest(t, r, UpdateConsumerRequest) w.WriteHeader(http.StatusOK) - _, err := fmt.Fprintf(w, UpdateConsumerResponse) + _, err := fmt.Fprint(w, UpdateConsumerResponse) th.AssertNoErr(t, err) }) } @@ -269,7 +269,7 @@ func HandleGetConsumer(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetConsumerResponse) + fmt.Fprint(w, GetConsumerResponse) }) } @@ -306,7 +306,7 @@ func HandleListConsumers(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListConsumersResponse) + fmt.Fprint(w, ListConsumersResponse) }) } @@ -329,7 +329,7 @@ func HandleRequestToken(t *testing.T) { w.Header().Set("Content-Type", oauth1.OAuth1TokenContentType) w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, `oauth_token=29971f&oauth_token_secret=238eb8&oauth_expires_at=2013-09-11T06:07:51.501805Z`) + fmt.Fprint(w, `oauth_token=29971f&oauth_token_secret=238eb8&oauth_expires_at=2013-09-11T06:07:51.501805Z`) }) } @@ -343,7 +343,7 @@ func HandleAuthorizeToken(t *testing.T) { th.TestJSONRequest(t, r, AuthorizeTokenRequest) w.WriteHeader(http.StatusOK) - _, err := fmt.Fprintf(w, AuthorizeTokenResponse) + _, err := fmt.Fprint(w, AuthorizeTokenResponse) th.AssertNoErr(t, err) }) } @@ -366,7 +366,7 @@ func HandleCreateAccessToken(t *testing.T) { w.Header().Set("Content-Type", oauth1.OAuth1TokenContentType) w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, `oauth_token=accd36&oauth_token_secret=aa47da&oauth_expires_at=2013-09-11T06:07:51.501805Z`) + fmt.Fprint(w, `oauth_token=accd36&oauth_token_secret=aa47da&oauth_expires_at=2013-09-11T06:07:51.501805Z`) }) } @@ -380,7 +380,7 @@ func HandleGetAccessToken(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetUserAccessTokenResponse) + fmt.Fprint(w, GetUserAccessTokenResponse) }) } @@ -405,7 +405,7 @@ func HandleListAccessTokens(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListUserAccessTokensResponse) + fmt.Fprint(w, ListUserAccessTokensResponse) }) } @@ -419,7 +419,7 @@ func HandleListAccessTokenRoles(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListUserAccessTokenRolesResponse) + fmt.Fprint(w, ListUserAccessTokenRolesResponse) }) } @@ -433,7 +433,7 @@ func HandleGetAccessTokenRole(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListUserAccessTokenRoleResponse) + fmt.Fprint(w, ListUserAccessTokenRoleResponse) }) } @@ -449,6 +449,6 @@ func HandleAuthenticate(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, tokens.TokenOutput) + fmt.Fprint(w, tokens.TokenOutput) }) } diff --git a/openstack/identity/v3/policies/testing/fixtures_test.go b/openstack/identity/v3/policies/testing/fixtures_test.go index 2ebc6c6c41..d261ed865c 100644 --- a/openstack/identity/v3/policies/testing/fixtures_test.go +++ b/openstack/identity/v3/policies/testing/fixtures_test.go @@ -164,9 +164,9 @@ func HandleListPoliciesSuccessfully(t *testing.T) { w.WriteHeader(http.StatusOK) switch r.URL.Query().Get("type") { case "": - fmt.Fprintf(w, ListOutput) + fmt.Fprint(w, ListOutput) case "application/json": - fmt.Fprintf(w, ListWithFilterOutput) + fmt.Fprint(w, ListWithFilterOutput) default: w.WriteHeader(http.StatusBadRequest) } @@ -182,7 +182,7 @@ func HandleCreatePolicySuccessfully(t *testing.T) { th.TestJSONRequest(t, r, CreateRequest) w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } @@ -197,7 +197,7 @@ func HandleGetPolicySuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }, ) } @@ -212,7 +212,7 @@ func HandleUpdatePolicySuccessfully(t *testing.T) { th.TestJSONRequest(t, r, UpdateRequest) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdateOutput) + fmt.Fprint(w, UpdateOutput) }, ) } diff --git a/openstack/identity/v3/projectendpoints/testing/requests_test.go b/openstack/identity/v3/projectendpoints/testing/requests_test.go index 9a9c17139f..2e8f6aad4c 100644 --- a/openstack/identity/v3/projectendpoints/testing/requests_test.go +++ b/openstack/identity/v3/projectendpoints/testing/requests_test.go @@ -37,7 +37,7 @@ func TestListEndpoints(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "endpoints": [ { diff --git a/openstack/identity/v3/projects/testing/fixtures_test.go b/openstack/identity/v3/projects/testing/fixtures_test.go index a54edfe21f..568305008a 100644 --- a/openstack/identity/v3/projects/testing/fixtures_test.go +++ b/openstack/identity/v3/projects/testing/fixtures_test.go @@ -285,7 +285,7 @@ func HandleListAvailableProjectsSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListAvailableOutput) + fmt.Fprint(w, ListAvailableOutput) }) } @@ -299,7 +299,7 @@ func HandleListProjectsSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListOutput) + fmt.Fprint(w, ListOutput) }) } @@ -313,7 +313,7 @@ func HandleGetProjectSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } @@ -326,7 +326,7 @@ func HandleCreateProjectSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, CreateRequest) w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } @@ -350,7 +350,7 @@ func HandleUpdateProjectSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, UpdateRequest) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdateOutput) + fmt.Fprint(w, UpdateOutput) }) } @@ -360,7 +360,7 @@ func HandleListProjectTagsSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListTagsOutput) + fmt.Fprint(w, ListTagsOutput) }) } @@ -371,7 +371,7 @@ func HandleModifyProjectTagsSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, ModifyProjectTagsRequest) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ModifyProjectTagsOutput) + fmt.Fprint(w, ModifyProjectTagsOutput) }) } func HandleDeleteProjectTagsSuccessfully(t *testing.T) { diff --git a/openstack/identity/v3/regions/testing/fixtures_test.go b/openstack/identity/v3/regions/testing/fixtures_test.go index a4c3a40c38..633ae86dcb 100644 --- a/openstack/identity/v3/regions/testing/fixtures_test.go +++ b/openstack/identity/v3/regions/testing/fixtures_test.go @@ -172,7 +172,7 @@ func HandleListRegionsSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListOutput) + fmt.Fprint(w, ListOutput) }) } @@ -186,7 +186,7 @@ func HandleGetRegionSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } @@ -199,7 +199,7 @@ func HandleCreateRegionSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, CreateRequest) w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } @@ -212,7 +212,7 @@ func HandleUpdateRegionSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, UpdateRequest) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdateOutput) + fmt.Fprint(w, UpdateOutput) }) } diff --git a/openstack/identity/v3/registeredlimits/testing/fixtures_test.go b/openstack/identity/v3/registeredlimits/testing/fixtures_test.go index 37e11ed6eb..1bcfc5e867 100644 --- a/openstack/identity/v3/registeredlimits/testing/fixtures_test.go +++ b/openstack/identity/v3/registeredlimits/testing/fixtures_test.go @@ -163,7 +163,7 @@ func HandleListRegisteredLimitsSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListOutput) + fmt.Fprint(w, ListOutput) }) } @@ -177,7 +177,7 @@ func HandleGetRegisteredLimitSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } @@ -190,7 +190,7 @@ func HandleCreateRegisteredLimitSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, CreateRequest) w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreateOutput) + fmt.Fprint(w, CreateOutput) }) } @@ -214,6 +214,6 @@ func HandleUpdateRegisteredLimitSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, UpdateRequest) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdateOutput) + fmt.Fprint(w, UpdateOutput) }) } diff --git a/openstack/identity/v3/roles/testing/fixtures_test.go b/openstack/identity/v3/roles/testing/fixtures_test.go index 755f14d4e8..32fe745a94 100644 --- a/openstack/identity/v3/roles/testing/fixtures_test.go +++ b/openstack/identity/v3/roles/testing/fixtures_test.go @@ -350,7 +350,7 @@ func HandleListRolesSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListOutput) + fmt.Fprint(w, ListOutput) }) } @@ -364,7 +364,7 @@ func HandleGetRoleSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } @@ -377,7 +377,7 @@ func HandleCreateRoleSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, CreateRequest) w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } @@ -390,7 +390,7 @@ func HandleUpdateRoleSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, UpdateRequest) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdateOutput) + fmt.Fprint(w, UpdateOutput) }) } @@ -499,7 +499,7 @@ func HandleListRoleAssignmentsSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListAssignmentOutput) + fmt.Fprint(w, ListAssignmentOutput) }) } @@ -514,7 +514,7 @@ func HandleListRoleAssignmentsWithNamesSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListAssignmentWithNamesOutput) + fmt.Fprint(w, ListAssignmentWithNamesOutput) }) } @@ -529,7 +529,7 @@ func HandleListRoleAssignmentsWithSubtreeSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListAssignmentOutput) + fmt.Fprint(w, ListAssignmentOutput) }) } @@ -557,7 +557,7 @@ func HandleListAssignmentsOnResourceSuccessfully_ProjectsUsers(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListAssignmentsOnResourceOutput) + fmt.Fprint(w, ListAssignmentsOnResourceOutput) } th.Mux.HandleFunc("/projects/{project_id}/users/{user_id}/roles", fn) @@ -571,7 +571,7 @@ func HandleListAssignmentsOnResourceSuccessfully_ProjectsGroups(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListAssignmentsOnResourceOutput) + fmt.Fprint(w, ListAssignmentsOnResourceOutput) } th.Mux.HandleFunc("/projects/{project_id}/groups/{group_id}/roles", fn) @@ -585,7 +585,7 @@ func HandleListAssignmentsOnResourceSuccessfully_DomainsUsers(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListAssignmentsOnResourceOutput) + fmt.Fprint(w, ListAssignmentsOnResourceOutput) } th.Mux.HandleFunc("/domains/{domain_id}/users/{user_id}/roles", fn) @@ -599,7 +599,7 @@ func HandleListAssignmentsOnResourceSuccessfully_DomainsGroups(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListAssignmentsOnResourceOutput) + fmt.Fprint(w, ListAssignmentsOnResourceOutput) } th.Mux.HandleFunc("/domains/{domain_id}/groups/{group_id}/roles", fn) @@ -635,7 +635,7 @@ func HandleCreateRoleInferenceRule(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreateRoleInferenceRuleOutput) + fmt.Fprint(w, CreateRoleInferenceRuleOutput) } th.Mux.HandleFunc("/roles/7ceab6192ea34a548cc71b24f72e762c/implies/97e2f5d38bc94842bc3da818c16762ed", fn) @@ -713,7 +713,7 @@ func HandleListRoleInferenceRules(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListRoleInferenceRulesOutput) + fmt.Fprint(w, ListRoleInferenceRulesOutput) } th.Mux.HandleFunc("/role_inferences", fn) @@ -737,7 +737,7 @@ func HandleGetRoleInferenceRule(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, CreateRoleInferenceRuleOutput) + fmt.Fprint(w, CreateRoleInferenceRuleOutput) } th.Mux.HandleFunc("/roles/7ceab6192ea34a548cc71b24f72e762c/implies/97e2f5d38bc94842bc3da818c16762ed", fn) diff --git a/openstack/identity/v3/services/testing/fixtures_test.go b/openstack/identity/v3/services/testing/fixtures_test.go index da713482f8..0a9274c500 100644 --- a/openstack/identity/v3/services/testing/fixtures_test.go +++ b/openstack/identity/v3/services/testing/fixtures_test.go @@ -164,7 +164,7 @@ func HandleListServicesSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListOutput) + fmt.Fprint(w, ListOutput) }) } @@ -178,7 +178,7 @@ func HandleGetServiceSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } @@ -191,7 +191,7 @@ func HandleCreateServiceSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, CreateRequest) w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } @@ -204,6 +204,6 @@ func HandleUpdateServiceSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, UpdateRequest) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdateOutput) + fmt.Fprint(w, UpdateOutput) }) } diff --git a/openstack/identity/v3/tokens/testing/requests_test.go b/openstack/identity/v3/tokens/testing/requests_test.go index c0aafb9ad4..8bb00fbffa 100644 --- a/openstack/identity/v3/tokens/testing/requests_test.go +++ b/openstack/identity/v3/tokens/testing/requests_test.go @@ -30,7 +30,7 @@ func authTokenPost(t *testing.T, options tokens.AuthOptions, scope *tokens.Scope th.TestJSONRequest(t, r, requestJSON) w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, `{ + fmt.Fprint(w, `{ "token": { "expires_at": "2014-10-02T13:45:00.000000Z" } @@ -369,7 +369,7 @@ func TestCreateUserIDPasswordTrustID(t *testing.T) { th.TestJSONRequest(t, r, requestJSON) w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, responseJSON) + fmt.Fprint(w, responseJSON) }) ao := gophercloud.AuthOptions{ @@ -525,7 +525,7 @@ func TestCreateExtractsTokenFromResponse(t *testing.T) { w.Header().Add("X-Subject-Token", "aaa111") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, `{ + fmt.Fprint(w, `{ "token": { "expires_at": "2014-10-02T13:45:00.000000Z" } @@ -670,7 +670,7 @@ func TestGetRequest(t *testing.T) { th.TestHeader(t, r, "X-Subject-Token", "abcdef12345") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "token": { "expires_at": "2014-08-29T13:10:01.000000Z" } } `) }) @@ -779,7 +779,7 @@ func TestNoTokenInResponse(t *testing.T) { th.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, `{}`) + fmt.Fprint(w, `{}`) }) options := tokens.AuthOptions{UserID: "me", Password: "squirrel!"} diff --git a/openstack/identity/v3/trusts/testing/fixtures_test.go b/openstack/identity/v3/trusts/testing/fixtures_test.go index 6cc9a8a7d1..3e7e77fc3c 100644 --- a/openstack/identity/v3/trusts/testing/fixtures_test.go +++ b/openstack/identity/v3/trusts/testing/fixtures_test.go @@ -207,7 +207,7 @@ func HandleCreateTrust(t *testing.T) { th.TestJSONRequest(t, r, CreateRequest) w.WriteHeader(http.StatusCreated) - _, err := fmt.Fprintf(w, CreateResponse) + _, err := fmt.Fprint(w, CreateResponse) th.AssertNoErr(t, err) }) } @@ -221,7 +221,7 @@ func HandleCreateTrustNoExpire(t *testing.T) { th.TestJSONRequest(t, r, CreateRequestNoExpire) w.WriteHeader(http.StatusCreated) - _, err := fmt.Fprintf(w, CreateResponseNoExpire) + _, err := fmt.Fprint(w, CreateResponseNoExpire) th.AssertNoErr(t, err) }) } @@ -247,7 +247,7 @@ func HandleGetTrustSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetResponse) + fmt.Fprint(w, GetResponse) }) } @@ -317,7 +317,7 @@ func HandleListTrustsSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListResponse) + fmt.Fprint(w, ListResponse) }) } @@ -331,7 +331,7 @@ func HandleListTrustRolesSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListTrustRolesResponse) + fmt.Fprint(w, ListTrustRolesResponse) }) } @@ -345,7 +345,7 @@ func HandleGetTrustRoleSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetTrustRoleResponse) + fmt.Fprint(w, GetTrustRoleResponse) }) } diff --git a/openstack/identity/v3/users/testing/fixtures_test.go b/openstack/identity/v3/users/testing/fixtures_test.go index 023124cb79..faff58d4d0 100644 --- a/openstack/identity/v3/users/testing/fixtures_test.go +++ b/openstack/identity/v3/users/testing/fixtures_test.go @@ -382,7 +382,7 @@ func HandleListUsersSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListOutput) + fmt.Fprint(w, ListOutput) }) } @@ -396,7 +396,7 @@ func HandleGetUserSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } @@ -409,7 +409,7 @@ func HandleCreateUserSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, CreateRequest) w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } @@ -422,7 +422,7 @@ func HandleCreateNoOptionsUserSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, CreateNoOptionsRequest) w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, GetOutputNoOptions) + fmt.Fprint(w, GetOutputNoOptions) }) } @@ -435,7 +435,7 @@ func HandleUpdateUserSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, UpdateRequest) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdateOutput) + fmt.Fprint(w, UpdateOutput) }) } @@ -472,7 +472,7 @@ func HandleListUserGroupsSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListGroupsOutput) + fmt.Fprint(w, ListGroupsOutput) }) } @@ -519,7 +519,7 @@ func HandleListUserProjectsSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListProjectsOutput) + fmt.Fprint(w, ListProjectsOutput) }) } @@ -533,6 +533,6 @@ func HandleListInGroupSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListOutput) + fmt.Fprint(w, ListOutput) }) } diff --git a/openstack/image/v2/imageimport/testing/requests_test.go b/openstack/image/v2/imageimport/testing/requests_test.go index ae353ad0ac..74df12e548 100644 --- a/openstack/image/v2/imageimport/testing/requests_test.go +++ b/openstack/image/v2/imageimport/testing/requests_test.go @@ -22,7 +22,7 @@ func TestGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ImportGetResult) + fmt.Fprint(w, ImportGetResult) }) validImportMethods := []string{ @@ -49,7 +49,7 @@ func TestCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, `{}`) + fmt.Fprint(w, `{}`) }) opts := imageimport.CreateOpts{ diff --git a/openstack/image/v2/images/testing/fixtures_test.go b/openstack/image/v2/images/testing/fixtures_test.go index 0c9a7b0318..693f6b9965 100644 --- a/openstack/image/v2/images/testing/fixtures_test.go +++ b/openstack/image/v2/images/testing/fixtures_test.go @@ -130,7 +130,7 @@ func HandleImageListSuccessfully(t *testing.T) { addNext := false var imageJSON []string - fmt.Fprintf(w, `{"images": [`) + fmt.Fprint(w, `{"images": [`) for _, i := range images { if marker == "" || addNext { @@ -149,7 +149,7 @@ func HandleImageListSuccessfully(t *testing.T) { } } t.Logf("Writing out %v image(s)", len(imageJSON)) - fmt.Fprintf(w, strings.Join(imageJSON, ",")) + fmt.Fprint(w, strings.Join(imageJSON, ",")) fmt.Fprintf(w, `], "next": "/images?marker=%s&limit=%v", @@ -176,7 +176,7 @@ func HandleImageCreationSuccessfully(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, `{ + fmt.Fprint(w, `{ "status": "queued", "name": "Ubuntu 12.10", "protected": false, @@ -224,7 +224,7 @@ func HandleImageCreationSuccessfullyNulls(t *testing.T) { w.Header().Set("OpenStack-image-import-methods", "glance-direct,web-download") w.Header().Set("OpenStack-image-store-ids", "123,456") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, `{ + fmt.Fprint(w, `{ "architecture": "x86_64", "status": "queued", "name": "Ubuntu 12.10", @@ -258,7 +258,7 @@ func HandleImageGetSuccessfully(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, `{ + fmt.Fprint(w, `{ "status": "active", "name": "cirros-0.3.2-x86_64-disk", "tags": [], @@ -347,7 +347,7 @@ func HandleImageUpdateSuccessfully(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, `{ + fmt.Fprint(w, `{ "id": "da3b75d9-3f4a-40e7-8a2c-bfab23927dea", "name": "Fedora 17", "status": "active", @@ -389,7 +389,7 @@ func HandleImageListByTagsSuccessfully(t *testing.T) { w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, `{ + fmt.Fprint(w, `{ "images": [ { "status": "active", @@ -449,7 +449,7 @@ func HandleImageUpdatePropertiesSuccessfully(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, `{ + fmt.Fprint(w, `{ "id": "da3b75d9-3f4a-40e7-8a2c-bfab23927dea", "name": "Fedora 17", "status": "active", diff --git a/openstack/image/v2/members/testing/fixtures_test.go b/openstack/image/v2/members/testing/fixtures_test.go index 4100b186f4..6e0bd326e7 100644 --- a/openstack/image/v2/members/testing/fixtures_test.go +++ b/openstack/image/v2/members/testing/fixtures_test.go @@ -18,7 +18,7 @@ func HandleCreateImageMemberSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, `{"member": "8989447062e04a818baf9e073fd04fa7"}`) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, `{ + fmt.Fprint(w, `{ "created_at": "2013-09-20T19:22:19Z", "image_id": "da3b75d9-3f4a-40e7-8a2c-bfab23927dea", "member_id": "8989447062e04a818baf9e073fd04fa7", @@ -37,7 +37,7 @@ func HandleImageMemberList(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", fakeclient.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, `{ + fmt.Fprint(w, `{ "members": [ { "created_at": "2013-10-07T17:58:03Z", @@ -68,7 +68,7 @@ func HandleImageMemberEmptyList(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", fakeclient.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, `{ + fmt.Fprint(w, `{ "members": [], "schema": "/v2/schemas/members" }`) @@ -82,7 +82,7 @@ func HandleImageMemberDetails(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", fakeclient.TokenID) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, `{ + fmt.Fprint(w, `{ "status": "pending", "created_at": "2013-11-26T07:21:21Z", "updated_at": "2013-11-26T07:21:21Z", @@ -120,7 +120,7 @@ func HandleImageMemberUpdate(t *testing.T) *CallsCounter { w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, `{ + fmt.Fprint(w, `{ "status": "accepted", "created_at": "2013-11-26T07:21:21Z", "updated_at": "2013-11-26T07:21:21Z", diff --git a/openstack/image/v2/tasks/testing/requests_test.go b/openstack/image/v2/tasks/testing/requests_test.go index feb74068bc..f930304427 100644 --- a/openstack/image/v2/tasks/testing/requests_test.go +++ b/openstack/image/v2/tasks/testing/requests_test.go @@ -24,7 +24,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, TasksListResult) + fmt.Fprint(w, TasksListResult) }) count := 0 @@ -64,7 +64,7 @@ func TestGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, TasksGetResult) + fmt.Fprint(w, TasksGetResult) }) s, err := tasks.Get(context.TODO(), fakeclient.ServiceClient(), "1252f636-1246-4319-bfba-c47cde0efbe0").Extract() @@ -102,7 +102,7 @@ func TestCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, TaskCreateResult) + fmt.Fprint(w, TaskCreateResult) }) opts := tasks.CreateOpts{ diff --git a/openstack/keymanager/v1/acls/testing/fixtures_test.go b/openstack/keymanager/v1/acls/testing/fixtures_test.go index 7db2b37b4f..89b6ea7d4d 100644 --- a/openstack/keymanager/v1/acls/testing/fixtures_test.go +++ b/openstack/keymanager/v1/acls/testing/fixtures_test.go @@ -75,7 +75,7 @@ func HandleGetSecretACLSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetResponse) + fmt.Fprint(w, GetResponse) }) } @@ -89,7 +89,7 @@ func HandleGetContainerACLSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetResponse) + fmt.Fprint(w, GetResponse) }) } @@ -102,7 +102,7 @@ func HandleSetSecretACLSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, SetRequest) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, SecretSetResponse) + fmt.Fprint(w, SecretSetResponse) }) } @@ -115,7 +115,7 @@ func HandleSetContainerACLSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, SetRequest) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ContainerSetResponse) + fmt.Fprint(w, ContainerSetResponse) }) } @@ -128,7 +128,7 @@ func HandleUpdateSecretACLSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, UpdateRequest) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, SecretSetResponse) + fmt.Fprint(w, SecretSetResponse) }) } @@ -141,7 +141,7 @@ func HandleUpdateContainerACLSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, UpdateRequest) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ContainerSetResponse) + fmt.Fprint(w, ContainerSetResponse) }) } diff --git a/openstack/keymanager/v1/containers/testing/fixtures_test.go b/openstack/keymanager/v1/containers/testing/fixtures_test.go index 4b3997f786..d290a5a9a6 100644 --- a/openstack/keymanager/v1/containers/testing/fixtures_test.go +++ b/openstack/keymanager/v1/containers/testing/fixtures_test.go @@ -235,7 +235,7 @@ func HandleListContainersSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListResponse) + fmt.Fprint(w, ListResponse) }) } @@ -249,7 +249,7 @@ func HandleGetContainerSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetResponse) + fmt.Fprint(w, GetResponse) }) } @@ -262,7 +262,7 @@ func HandleCreateContainerSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, CreateRequest) w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, GetResponse) + fmt.Fprint(w, GetResponse) }) } @@ -288,7 +288,7 @@ func HandleListConsumersSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListConsumersResponse) + fmt.Fprint(w, ListConsumersResponse) }) } @@ -302,7 +302,7 @@ func HandleCreateConsumerSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, CreateConsumerRequest) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, CreateConsumerResponse) + fmt.Fprint(w, CreateConsumerResponse) }) } @@ -316,6 +316,6 @@ func HandleDeleteConsumerSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, CreateConsumerRequest) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetResponse) + fmt.Fprint(w, GetResponse) }) } diff --git a/openstack/keymanager/v1/orders/testing/fixtures_test.go b/openstack/keymanager/v1/orders/testing/fixtures_test.go index 636fe7eb3f..7eb14e0edf 100644 --- a/openstack/keymanager/v1/orders/testing/fixtures_test.go +++ b/openstack/keymanager/v1/orders/testing/fixtures_test.go @@ -143,7 +143,7 @@ func HandleListOrdersSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListResponse) + fmt.Fprint(w, ListResponse) }) } @@ -157,7 +157,7 @@ func HandleGetOrderSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetResponse) + fmt.Fprint(w, GetResponse) }) } @@ -170,7 +170,7 @@ func HandleCreateOrderSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, CreateRequest) w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, GetResponse) + fmt.Fprint(w, GetResponse) }) } diff --git a/openstack/keymanager/v1/secrets/testing/fixtures_test.go b/openstack/keymanager/v1/secrets/testing/fixtures_test.go index ff13102354..ed0e9ffad0 100644 --- a/openstack/keymanager/v1/secrets/testing/fixtures_test.go +++ b/openstack/keymanager/v1/secrets/testing/fixtures_test.go @@ -198,7 +198,7 @@ func HandleListSecretsSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListResponse) + fmt.Fprint(w, ListResponse) }) } @@ -212,7 +212,7 @@ func HandleGetSecretSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetResponse) + fmt.Fprint(w, GetResponse) }) } @@ -225,7 +225,7 @@ func HandleGetPayloadSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "text/plain") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetPayloadResponse) + fmt.Fprint(w, GetPayloadResponse) }) } @@ -238,7 +238,7 @@ func HandleCreateSecretSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, CreateRequest) w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreateResponse) + fmt.Fprint(w, CreateResponse) }) } @@ -277,7 +277,7 @@ func HandleGetMetadataSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetMetadataResponse) + fmt.Fprint(w, GetMetadataResponse) }) } @@ -293,7 +293,7 @@ func HandleCreateMetadataSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreateMetadataResponse) + fmt.Fprint(w, CreateMetadataResponse) }) } @@ -308,7 +308,7 @@ func HandleGetMetadatumSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, MetadatumResponse) + fmt.Fprint(w, MetadatumResponse) }) } @@ -324,7 +324,7 @@ func HandleCreateMetadatumSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, MetadatumResponse) + fmt.Fprint(w, MetadatumResponse) }) } @@ -340,7 +340,7 @@ func HandleUpdateMetadatumSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, MetadatumResponse) + fmt.Fprint(w, MetadatumResponse) }) } diff --git a/openstack/loadbalancer/v2/amphorae/testing/fixtures_test.go b/openstack/loadbalancer/v2/amphorae/testing/fixtures_test.go index 8ffafa253e..049f0697bf 100644 --- a/openstack/loadbalancer/v2/amphorae/testing/fixtures_test.go +++ b/openstack/loadbalancer/v2/amphorae/testing/fixtures_test.go @@ -150,9 +150,9 @@ func HandleAmphoraListSuccessfully(t *testing.T) { marker := r.Form.Get("marker") switch marker { case "": - fmt.Fprintf(w, AmphoraeListBody) + fmt.Fprint(w, AmphoraeListBody) case "7f890893-ced0-46ed-8697-33415d070e5a": - fmt.Fprintf(w, `{ "amphorae": [] }`) + fmt.Fprint(w, `{ "amphorae": [] }`) default: t.Fatalf("/v2.0/octavia/amphorae invoked with unexpected marker=[%s]", marker) } @@ -166,7 +166,7 @@ func HandleAmphoraGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestHeader(t, r, "Accept", "application/json") - fmt.Fprintf(w, SingleAmphoraBody) + fmt.Fprint(w, SingleAmphoraBody) }) } diff --git a/openstack/loadbalancer/v2/apiversions/testing/fixture.go b/openstack/loadbalancer/v2/apiversions/testing/fixture.go index d21507dbab..b427378d95 100644 --- a/openstack/loadbalancer/v2/apiversions/testing/fixture.go +++ b/openstack/loadbalancer/v2/apiversions/testing/fixture.go @@ -88,6 +88,6 @@ func MockListResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, OctaviaAllAPIVersionsResponse) + fmt.Fprint(w, OctaviaAllAPIVersionsResponse) }) } diff --git a/openstack/loadbalancer/v2/flavorprofiles/testing/fixtures.go b/openstack/loadbalancer/v2/flavorprofiles/testing/fixtures.go index adbdf1b7b3..3558a21919 100644 --- a/openstack/loadbalancer/v2/flavorprofiles/testing/fixtures.go +++ b/openstack/loadbalancer/v2/flavorprofiles/testing/fixtures.go @@ -94,9 +94,9 @@ func HandleFlavorProfileListSuccessfully(t *testing.T) { marker := r.Form.Get("marker") switch marker { case "": - fmt.Fprintf(w, FlavorProfilesListBody) + fmt.Fprint(w, FlavorProfilesListBody) case "3a0d060b-fcec-4250-9ab6-940b806a12dd": - fmt.Fprintf(w, `{ "flavors": [] }`) + fmt.Fprint(w, `{ "flavors": [] }`) default: t.Fatalf("/v2.0/lbaas/flavors invoked with unexpected marker=[%s]", marker) } @@ -117,7 +117,7 @@ func HandleFlavorProfileCreationSuccessfully(t *testing.T, response string) { w.WriteHeader(http.StatusAccepted) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, response) + fmt.Fprint(w, response) }) } @@ -127,7 +127,7 @@ func HandleFlavorProfileGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestHeader(t, r, "Accept", "application/json") - fmt.Fprintf(w, SingleFlavorProfileBody) + fmt.Fprint(w, SingleFlavorProfileBody) }) } @@ -154,6 +154,6 @@ func HandleFlavorProfileUpdateSuccessfully(t *testing.T) { } }`) - fmt.Fprintf(w, PostUpdateFlavorBody) + fmt.Fprint(w, PostUpdateFlavorBody) }) } diff --git a/openstack/loadbalancer/v2/flavors/testing/fixtures.go b/openstack/loadbalancer/v2/flavors/testing/fixtures.go index a3169d7ece..1ec935c156 100644 --- a/openstack/loadbalancer/v2/flavors/testing/fixtures.go +++ b/openstack/loadbalancer/v2/flavors/testing/fixtures.go @@ -102,9 +102,9 @@ func HandleFlavorListSuccessfully(t *testing.T) { marker := r.Form.Get("marker") switch marker { case "": - fmt.Fprintf(w, FlavorsListBody) + fmt.Fprint(w, FlavorsListBody) case "3a0d060b-fcec-4250-9ab6-940b806a12dd": - fmt.Fprintf(w, `{ "flavors": [] }`) + fmt.Fprint(w, `{ "flavors": [] }`) default: t.Fatalf("/v2.0/lbaas/flavors invoked with unexpected marker=[%s]", marker) } @@ -126,7 +126,7 @@ func HandleFlavorCreationSuccessfully(t *testing.T, response string) { w.WriteHeader(http.StatusAccepted) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, response) + fmt.Fprint(w, response) }) } @@ -136,7 +136,7 @@ func HandleFlavorGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestHeader(t, r, "Accept", "application/json") - fmt.Fprintf(w, SingleFlavorBody) + fmt.Fprint(w, SingleFlavorBody) }) } @@ -163,6 +163,6 @@ func HandleFlavorUpdateSuccessfully(t *testing.T) { } }`) - fmt.Fprintf(w, PostUpdateFlavorBody) + fmt.Fprint(w, PostUpdateFlavorBody) }) } diff --git a/openstack/loadbalancer/v2/flavors/testing/requests_test.go b/openstack/loadbalancer/v2/flavors/testing/requests_test.go index fd668a2134..bc73b1271d 100644 --- a/openstack/loadbalancer/v2/flavors/testing/requests_test.go +++ b/openstack/loadbalancer/v2/flavors/testing/requests_test.go @@ -69,7 +69,7 @@ func TestListFlavorsEnabled(t *testing.T) { t.Errorf("Expected enabled=%s got %q", testCases[cases], enabled) } cases++ - fmt.Fprintf(w, `{"flavorprofiles":[]}`) + fmt.Fprint(w, `{"flavorprofiles":[]}`) }) }() diff --git a/openstack/loadbalancer/v2/l7policies/testing/fixtures_test.go b/openstack/loadbalancer/v2/l7policies/testing/fixtures_test.go index a1773287f9..56b35cd0e0 100644 --- a/openstack/loadbalancer/v2/l7policies/testing/fixtures_test.go +++ b/openstack/loadbalancer/v2/l7policies/testing/fixtures_test.go @@ -131,7 +131,7 @@ func HandleL7PolicyCreationSuccessfully(t *testing.T, response string) { w.WriteHeader(http.StatusAccepted) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, response) + fmt.Fprint(w, response) }) } @@ -218,9 +218,9 @@ func HandleL7PolicyListSuccessfully(t *testing.T) { marker := r.Form.Get("marker") switch marker { case "": - fmt.Fprintf(w, L7PoliciesListBody) + fmt.Fprint(w, L7PoliciesListBody) case "45e08a3e-a78f-4b40-a229-1e7e23eee1ab": - fmt.Fprintf(w, `{ "l7policies": [] }`) + fmt.Fprint(w, `{ "l7policies": [] }`) default: t.Fatalf("/v2.0/lbaas/l7policies invoked with unexpected marker=[%s]", marker) } @@ -234,7 +234,7 @@ func HandleL7PolicyGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestHeader(t, r, "Accept", "application/json") - fmt.Fprintf(w, SingleL7PolicyBody) + fmt.Fprint(w, SingleL7PolicyBody) }) } @@ -263,7 +263,7 @@ func HandleL7PolicyUpdateSuccessfully(t *testing.T) { } }`) - fmt.Fprintf(w, PostUpdateL7PolicyBody) + fmt.Fprint(w, PostUpdateL7PolicyBody) }) } @@ -281,7 +281,7 @@ func HandleL7PolicyUpdateNullRedirectURLSuccessfully(t *testing.T) { } }`) - fmt.Fprintf(w, PostUpdateL7PolicyNullRedirectURLBody) + fmt.Fprint(w, PostUpdateL7PolicyNullRedirectURLBody) }) } @@ -317,7 +317,7 @@ func HandleRuleCreationSuccessfully(t *testing.T, response string) { w.WriteHeader(http.StatusAccepted) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, response) + fmt.Fprint(w, response) }) } @@ -362,9 +362,9 @@ func HandleRuleListSuccessfully(t *testing.T) { marker := r.Form.Get("marker") switch marker { case "": - fmt.Fprintf(w, RulesListBody) + fmt.Fprint(w, RulesListBody) case "45e08a3e-a78f-4b40-a229-1e7e23eee1ab": - fmt.Fprintf(w, `{ "rules": [] }`) + fmt.Fprint(w, `{ "rules": [] }`) default: t.Fatalf("/v2.0/lbaas/l7policies/8a1412f0-4c32-4257-8b07-af4770b604fd/rules invoked with unexpected marker=[%s]", marker) } @@ -378,7 +378,7 @@ func HandleRuleGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestHeader(t, r, "Accept", "application/json") - fmt.Fprintf(w, SingleRuleBody) + fmt.Fprint(w, SingleRuleBody) }) } @@ -425,6 +425,6 @@ func HandleRuleUpdateSuccessfully(t *testing.T) { } }`) - fmt.Fprintf(w, PostUpdateRuleBody) + fmt.Fprint(w, PostUpdateRuleBody) }) } diff --git a/openstack/loadbalancer/v2/listeners/testing/fixtures_test.go b/openstack/loadbalancer/v2/listeners/testing/fixtures_test.go index edda9b2bac..9f85649411 100644 --- a/openstack/loadbalancer/v2/listeners/testing/fixtures_test.go +++ b/openstack/loadbalancer/v2/listeners/testing/fixtures_test.go @@ -218,9 +218,9 @@ func HandleListenerListSuccessfully(t *testing.T) { marker := r.Form.Get("marker") switch marker { case "": - fmt.Fprintf(w, ListenersListBody) + fmt.Fprint(w, ListenersListBody) case "45e08a3e-a78f-4b40-a229-1e7e23eee1ab": - fmt.Fprintf(w, `{ "listeners": [] }`) + fmt.Fprint(w, `{ "listeners": [] }`) default: t.Fatalf("/v2.0/lbaas/listeners invoked with unexpected marker=[%s]", marker) } @@ -255,7 +255,7 @@ func HandleListenerCreationSuccessfully(t *testing.T, response string) { w.WriteHeader(http.StatusAccepted) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, response) + fmt.Fprint(w, response) }) } @@ -266,7 +266,7 @@ func HandleListenerGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestHeader(t, r, "Accept", "application/json") - fmt.Fprintf(w, SingleListenerBody) + fmt.Fprint(w, SingleListenerBody) }) } @@ -304,7 +304,7 @@ func HandleListenerUpdateSuccessfully(t *testing.T) { } }`) - fmt.Fprintf(w, PostUpdateListenerBody) + fmt.Fprint(w, PostUpdateListenerBody) }) } @@ -315,6 +315,6 @@ func HandleListenerGetStatsTree(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestHeader(t, r, "Accept", "application/json") - fmt.Fprintf(w, GetListenerStatsBody) + fmt.Fprint(w, GetListenerStatsBody) }) } diff --git a/openstack/loadbalancer/v2/loadbalancers/testing/fixtures_test.go b/openstack/loadbalancer/v2/loadbalancers/testing/fixtures_test.go index d4f714f7c5..76ef3ec2a7 100644 --- a/openstack/loadbalancer/v2/loadbalancers/testing/fixtures_test.go +++ b/openstack/loadbalancer/v2/loadbalancers/testing/fixtures_test.go @@ -453,9 +453,9 @@ func HandleLoadbalancerListSuccessfully(t *testing.T) { marker := r.Form.Get("marker") switch marker { case "": - fmt.Fprintf(w, LoadbalancersListBody) + fmt.Fprint(w, LoadbalancersListBody) case "45e08a3e-a78f-4b40-a229-1e7e23eee1ab": - fmt.Fprintf(w, `{ "loadbalancers": [] }`) + fmt.Fprint(w, `{ "loadbalancers": [] }`) default: t.Fatalf("/v2.0/lbaas/loadbalancers invoked with unexpected marker=[%s]", marker) } @@ -533,7 +533,7 @@ func HandleFullyPopulatedLoadbalancerCreationSuccessfully(t *testing.T, response w.WriteHeader(http.StatusAccepted) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, response) + fmt.Fprint(w, response) }) } @@ -559,7 +559,7 @@ func HandleLoadbalancerCreationSuccessfully(t *testing.T, response string) { w.WriteHeader(http.StatusAccepted) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, response) + fmt.Fprint(w, response) }) } @@ -570,7 +570,7 @@ func HandleLoadbalancerGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestHeader(t, r, "Accept", "application/json") - fmt.Fprintf(w, SingleLoadbalancerBody) + fmt.Fprint(w, SingleLoadbalancerBody) }) } @@ -581,7 +581,7 @@ func HandleLoadbalancerGetStatusesTree(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestHeader(t, r, "Accept", "application/json") - fmt.Fprintf(w, GetLoadbalancerStatusesBody) + fmt.Fprint(w, GetLoadbalancerStatusesBody) }) } @@ -609,7 +609,7 @@ func HandleLoadbalancerUpdateSuccessfully(t *testing.T) { } }`) - fmt.Fprintf(w, PostUpdateLoadbalancerBody) + fmt.Fprint(w, PostUpdateLoadbalancerBody) }) } @@ -620,7 +620,7 @@ func HandleLoadbalancerGetStatsTree(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestHeader(t, r, "Accept", "application/json") - fmt.Fprintf(w, GetLoadbalancerStatsBody) + fmt.Fprint(w, GetLoadbalancerStatsBody) }) } diff --git a/openstack/loadbalancer/v2/monitors/testing/fixtures_test.go b/openstack/loadbalancer/v2/monitors/testing/fixtures_test.go index 9526b9cbca..6b12d2c11c 100644 --- a/openstack/loadbalancer/v2/monitors/testing/fixtures_test.go +++ b/openstack/loadbalancer/v2/monitors/testing/fixtures_test.go @@ -152,9 +152,9 @@ func HandleHealthmonitorListSuccessfully(t *testing.T) { marker := r.Form.Get("marker") switch marker { case "": - fmt.Fprintf(w, HealthmonitorsListBody) + fmt.Fprint(w, HealthmonitorsListBody) case "556c8345-28d8-4f84-a246-e04380b0461d": - fmt.Fprintf(w, `{ "healthmonitors": [] }`) + fmt.Fprint(w, `{ "healthmonitors": [] }`) default: t.Fatalf("/v2.0/lbaas/healthmonitors invoked with unexpected marker=[%s]", marker) } @@ -184,7 +184,7 @@ func HandleHealthmonitorCreationSuccessfully(t *testing.T, response string) { w.WriteHeader(http.StatusAccepted) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, response) + fmt.Fprint(w, response) }) } @@ -195,7 +195,7 @@ func HandleHealthmonitorGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestHeader(t, r, "Accept", "application/json") - fmt.Fprintf(w, SingleHealthmonitorBody) + fmt.Fprint(w, SingleHealthmonitorBody) }) } @@ -228,6 +228,6 @@ func HandleHealthmonitorUpdateSuccessfully(t *testing.T) { } }`) - fmt.Fprintf(w, PostUpdateHealthmonitorBody) + fmt.Fprint(w, PostUpdateHealthmonitorBody) }) } diff --git a/openstack/loadbalancer/v2/pools/testing/fixtures_test.go b/openstack/loadbalancer/v2/pools/testing/fixtures_test.go index 47d7c373f8..bcc582a638 100644 --- a/openstack/loadbalancer/v2/pools/testing/fixtures_test.go +++ b/openstack/loadbalancer/v2/pools/testing/fixtures_test.go @@ -145,9 +145,9 @@ func HandlePoolListSuccessfully(t *testing.T) { marker := r.Form.Get("marker") switch marker { case "": - fmt.Fprintf(w, PoolsListBody) + fmt.Fprint(w, PoolsListBody) case "45e08a3e-a78f-4b40-a229-1e7e23eee1ab": - fmt.Fprintf(w, `{ "pools": [] }`) + fmt.Fprint(w, `{ "pools": [] }`) default: t.Fatalf("/v2.0/lbaas/pools invoked with unexpected marker=[%s]", marker) } @@ -172,7 +172,7 @@ func HandlePoolCreationSuccessfully(t *testing.T, response string) { w.WriteHeader(http.StatusAccepted) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, response) + fmt.Fprint(w, response) }) } @@ -183,7 +183,7 @@ func HandlePoolGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestHeader(t, r, "Accept", "application/json") - fmt.Fprintf(w, SinglePoolBody) + fmt.Fprint(w, SinglePoolBody) }) } @@ -211,7 +211,7 @@ func HandlePoolUpdateSuccessfully(t *testing.T) { } }`) - fmt.Fprintf(w, PostUpdatePoolBody) + fmt.Fprint(w, PostUpdatePoolBody) }) } @@ -342,9 +342,9 @@ func HandleMemberListSuccessfully(t *testing.T) { marker := r.Form.Get("marker") switch marker { case "": - fmt.Fprintf(w, MembersListBody) + fmt.Fprint(w, MembersListBody) case "45e08a3e-a78f-4b40-a229-1e7e23eee1ab": - fmt.Fprintf(w, `{ "members": [] }`) + fmt.Fprint(w, `{ "members": [] }`) default: t.Fatalf("/v2.0/lbaas/pools/332abe93-f488-41ba-870b-2ac66be7f853/members invoked with unexpected marker=[%s]", marker) } @@ -370,7 +370,7 @@ func HandleMemberCreationSuccessfully(t *testing.T, response string) { w.WriteHeader(http.StatusAccepted) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, response) + fmt.Fprint(w, response) }) } @@ -381,7 +381,7 @@ func HandleMemberGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestHeader(t, r, "Accept", "application/json") - fmt.Fprintf(w, SingleMemberBody) + fmt.Fprint(w, SingleMemberBody) }) } @@ -409,7 +409,7 @@ func HandleMemberUpdateSuccessfully(t *testing.T) { } }`) - fmt.Fprintf(w, PostUpdateMemberBody) + fmt.Fprint(w, PostUpdateMemberBody) }) } diff --git a/openstack/loadbalancer/v2/providers/testing/fixtures_test.go b/openstack/loadbalancer/v2/providers/testing/fixtures_test.go index 64db9a39bf..b8a857e618 100644 --- a/openstack/loadbalancer/v2/providers/testing/fixtures_test.go +++ b/openstack/loadbalancer/v2/providers/testing/fixtures_test.go @@ -50,7 +50,7 @@ func HandleProviderListSuccessfully(t *testing.T) { marker := r.Form.Get("marker") switch marker { case "": - fmt.Fprintf(w, ProvidersListBody) + fmt.Fprint(w, ProvidersListBody) default: t.Fatalf("/v2.0/lbaas/providers invoked with unexpected marker=[%s]", marker) } diff --git a/openstack/loadbalancer/v2/quotas/testing/requests_test.go b/openstack/loadbalancer/v2/quotas/testing/requests_test.go index 64c819aecf..6f990428fc 100644 --- a/openstack/loadbalancer/v2/quotas/testing/requests_test.go +++ b/openstack/loadbalancer/v2/quotas/testing/requests_test.go @@ -23,7 +23,7 @@ func TestGet_1(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetResponseRaw_1) + fmt.Fprint(w, GetResponseRaw_1) }) q, err := quotas.Get(context.TODO(), fake.ServiceClient(), "0a73845280574ad389c292f6a74afa76").Extract() @@ -42,7 +42,7 @@ func TestGet_2(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetResponseRaw_2) + fmt.Fprint(w, GetResponseRaw_2) }) q, err := quotas.Get(context.TODO(), fake.ServiceClient(), "0a73845280574ad389c292f6a74afa76").Extract() @@ -61,7 +61,7 @@ func TestUpdate_1(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, UpdateRequestResponseRaw_1) + fmt.Fprint(w, UpdateRequestResponseRaw_1) }) q, err := quotas.Update(context.TODO(), fake.ServiceClient(), "0a73845280574ad389c292f6a74afa76", quotas.UpdateOpts{ @@ -89,7 +89,7 @@ func TestUpdate_2(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, UpdateRequestResponseRaw_2) + fmt.Fprint(w, UpdateRequestResponseRaw_2) }) q, err := quotas.Update(context.TODO(), fake.ServiceClient(), "0a73845280574ad389c292f6a74afa76", quotas.UpdateOpts{ diff --git a/openstack/messaging/v2/claims/testing/fixtures_test.go b/openstack/messaging/v2/claims/testing/fixtures_test.go index f713687892..5912ff64e6 100644 --- a/openstack/messaging/v2/claims/testing/fixtures_test.go +++ b/openstack/messaging/v2/claims/testing/fixtures_test.go @@ -93,7 +93,7 @@ func HandleCreateSuccessfully(t *testing.T) { w.WriteHeader(http.StatusCreated) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, CreateClaimResponse) + fmt.Fprint(w, CreateClaimResponse) }) } @@ -117,7 +117,7 @@ func HandleGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, GetClaimResponse) + fmt.Fprint(w, GetClaimResponse) }) } diff --git a/openstack/messaging/v2/messages/testing/fixtures_test.go b/openstack/messaging/v2/messages/testing/fixtures_test.go index a5a82db253..95cd47592b 100644 --- a/openstack/messaging/v2/messages/testing/fixtures_test.go +++ b/openstack/messaging/v2/messages/testing/fixtures_test.go @@ -229,7 +229,7 @@ func HandleCreateSuccessfully(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreateMessageResponse) + fmt.Fprint(w, CreateMessageResponse) }) } @@ -245,7 +245,7 @@ func HandleListSuccessfully(t *testing.T) { switch next { case fmt.Sprintf("/v2/queues/%s/messages?limit=1", QueueName): - fmt.Fprintf(w, ListMessagesResponse1) + fmt.Fprint(w, ListMessagesResponse1) case fmt.Sprintf("/v2/queues/%s/messages?marker=1", QueueName): fmt.Fprint(w, ListMessagesResponse2) case fmt.Sprintf("/v2/queues/%s/messages?marker=2", QueueName): @@ -262,7 +262,7 @@ func HandleGetMessagesSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, GetMessagesResponse) + fmt.Fprint(w, GetMessagesResponse) }) } @@ -274,7 +274,7 @@ func HandleGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, GetMessageResponse) + fmt.Fprint(w, GetMessageResponse) }) } @@ -299,7 +299,7 @@ func HandlePopSuccessfully(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, PopMessageResponse) + fmt.Fprint(w, PopMessageResponse) }) } diff --git a/openstack/messaging/v2/queues/testing/fixtures_test.go b/openstack/messaging/v2/queues/testing/fixtures_test.go index 2e9cf5e752..7abfdc35ba 100644 --- a/openstack/messaging/v2/queues/testing/fixtures_test.go +++ b/openstack/messaging/v2/queues/testing/fixtures_test.go @@ -226,7 +226,7 @@ func HandleListSuccessfully(t *testing.T) { switch next { case "/v2/queues?limit=1&with_count=true": - fmt.Fprintf(w, ListQueuesResponse1) + fmt.Fprint(w, ListQueuesResponse1) case "/v2/queues?marker=london": fmt.Fprint(w, ListQueuesResponse2) case "/v2/queues?marker=beijing": @@ -256,7 +256,7 @@ func HandleUpdateSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, UpdateQueueRequest) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, UpdateQueueResponse) + fmt.Fprint(w, UpdateQueueResponse) }) } @@ -268,7 +268,7 @@ func HandleGetSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, GetQueueResponse) + fmt.Fprint(w, GetQueueResponse) }) } @@ -290,7 +290,7 @@ func HandleGetStatsSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, GetStatsResponse) + fmt.Fprint(w, GetStatsResponse) }) } @@ -303,7 +303,7 @@ func HandleShareSuccessfully(t *testing.T) { th.TestJSONRequest(t, r, CreateShareRequest) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, CreateShareResponse) + fmt.Fprint(w, CreateShareResponse) }) } diff --git a/openstack/networking/v2/apiversions/testing/requests_test.go b/openstack/networking/v2/apiversions/testing/requests_test.go index c99c99488b..dbdf61d9fd 100644 --- a/openstack/networking/v2/apiversions/testing/requests_test.go +++ b/openstack/networking/v2/apiversions/testing/requests_test.go @@ -23,7 +23,7 @@ func TestListVersions(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "versions": [ { @@ -96,7 +96,7 @@ func TestAPIInfo(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "resources": [ { diff --git a/openstack/networking/v2/extensions/agents/testing/requests_test.go b/openstack/networking/v2/extensions/agents/testing/requests_test.go index 070ff1b184..41380edac7 100644 --- a/openstack/networking/v2/extensions/agents/testing/requests_test.go +++ b/openstack/networking/v2/extensions/agents/testing/requests_test.go @@ -25,7 +25,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, AgentsListResult) + fmt.Fprint(w, AgentsListResult) }) count := 0 @@ -66,7 +66,7 @@ func TestGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, AgentsGetResult) + fmt.Fprint(w, AgentsGetResult) }) s, err := agents.Get(context.TODO(), fake.ServiceClient(), "43583cf5-472e-4dc8-af5b-6aed4c94ee3a").Extract() @@ -106,7 +106,7 @@ func TestUpdate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, AgentsUpdateResult) + fmt.Fprint(w, AgentsUpdateResult) }) iTrue := true @@ -149,7 +149,7 @@ func TestListDHCPNetworks(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, AgentDHCPNetworksListResult) + fmt.Fprint(w, AgentDHCPNetworksListResult) }) s, err := agents.ListDHCPNetworks(context.TODO(), fake.ServiceClient(), "43583cf5-472e-4dc8-af5b-6aed4c94ee3a").Extract() @@ -223,7 +223,7 @@ func TestListBGPSpeakers(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListBGPSpeakersResult) + fmt.Fprint(w, ListBGPSpeakersResult) }) count := 0 @@ -305,7 +305,7 @@ func TestListDRAgentHostingBGPSpeakers(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListDRAgentHostingBGPSpeakersResult) + fmt.Fprint(w, ListDRAgentHostingBGPSpeakersResult) }) count := 0 @@ -342,7 +342,7 @@ func TestListL3Routers(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, AgentL3RoutersListResult) + fmt.Fprint(w, AgentL3RoutersListResult) }) s, err := agents.ListL3Routers(context.TODO(), fake.ServiceClient(), "43583cf5-472e-4dc8-af5b-6aed4c94ee3a").Extract() diff --git a/openstack/networking/v2/extensions/attributestags/testing/requests_test.go b/openstack/networking/v2/extensions/attributestags/testing/requests_test.go index e9dc3498fb..5f20bdff5f 100644 --- a/openstack/networking/v2/extensions/attributestags/testing/requests_test.go +++ b/openstack/networking/v2/extensions/attributestags/testing/requests_test.go @@ -25,7 +25,7 @@ func TestReplaceAll(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, attributestagsReplaceAllResult) + fmt.Fprint(w, attributestagsReplaceAllResult) }) opts := attributestags.ReplaceAllOpts{ @@ -48,7 +48,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, attributestagsListResult) + fmt.Fprint(w, attributestagsListResult) }) res, err := attributestags.List(context.TODO(), fake.ServiceClient(), "networks", "fakeid").Extract() diff --git a/openstack/networking/v2/extensions/bgp/peers/testing/requests_test.go b/openstack/networking/v2/extensions/bgp/peers/testing/requests_test.go index 3ec3faa391..f24a0a1a0c 100644 --- a/openstack/networking/v2/extensions/bgp/peers/testing/requests_test.go +++ b/openstack/networking/v2/extensions/bgp/peers/testing/requests_test.go @@ -23,7 +23,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListBGPPeersResult) + fmt.Fprint(w, ListBGPPeersResult) }) count := 0 @@ -54,7 +54,7 @@ func TestGet(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetBGPPeerResult) + fmt.Fprint(w, GetBGPPeerResult) }) s, err := peers.Get(context.TODO(), fake.ServiceClient(), bgpPeerID).Extract() @@ -74,7 +74,7 @@ func TestCreate(t *testing.T) { th.TestJSONRequest(t, r, CreateRequest) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreateResponse) + fmt.Fprint(w, CreateResponse) }) var opts peers.CreateOpts @@ -124,7 +124,7 @@ func TestUpdate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdateBGPPeerResponse) + fmt.Fprint(w, UpdateBGPPeerResponse) }) var opts peers.UpdateOpts diff --git a/openstack/networking/v2/extensions/bgp/speakers/testing/requests_test.go b/openstack/networking/v2/extensions/bgp/speakers/testing/requests_test.go index d163086a8a..0ace6b2403 100644 --- a/openstack/networking/v2/extensions/bgp/speakers/testing/requests_test.go +++ b/openstack/networking/v2/extensions/bgp/speakers/testing/requests_test.go @@ -23,7 +23,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListBGPSpeakerResult) + fmt.Fprint(w, ListBGPSpeakerResult) }) count := 0 @@ -54,7 +54,7 @@ func TestGet(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetBGPSpeakerResult) + fmt.Fprint(w, GetBGPSpeakerResult) }) s, err := speakers.Get(context.TODO(), fake.ServiceClient(), bgpSpeakerID).Extract() @@ -74,7 +74,7 @@ func TestCreate(t *testing.T) { th.TestJSONRequest(t, r, CreateRequest) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreateResponse) + fmt.Fprint(w, CreateResponse) }) opts := speakers.CreateOpts{ @@ -124,7 +124,7 @@ func TestUpdate(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetBGPSpeakerResult) + fmt.Fprint(w, GetBGPSpeakerResult) } else if r.Method == "PUT" { th.TestMethod(t, r, "PUT") th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) @@ -134,7 +134,7 @@ func TestUpdate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdateBGPSpeakerResponse) + fmt.Fprint(w, UpdateBGPSpeakerResponse) } else { panic("Unexpected Request") } @@ -168,7 +168,7 @@ func TestAddBGPPeer(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, AddRemoveBGPPeerJSON) + fmt.Fprint(w, AddRemoveBGPPeerJSON) }) opts := speakers.AddBGPPeerOpts{BGPPeerID: bgpPeerID} @@ -207,7 +207,7 @@ func TestGetAdvertisedRoutes(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetAdvertisedRoutesResult) + fmt.Fprint(w, GetAdvertisedRoutesResult) }) count := 0 @@ -249,7 +249,7 @@ func TestAddGatewayNetwork(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, AddRemoveGatewayNetworkJSON) + fmt.Fprint(w, AddRemoveGatewayNetworkJSON) }) opts := speakers.AddGatewayNetworkOpts{NetworkID: networkID} @@ -273,7 +273,7 @@ func TestRemoveGatewayNetwork(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, "") + fmt.Fprint(w, "") }) opts := speakers.RemoveGatewayNetworkOpts{NetworkID: networkID} diff --git a/openstack/networking/v2/extensions/bgpvpns/testing/requests_test.go b/openstack/networking/v2/extensions/bgpvpns/testing/requests_test.go index 3b39e7cee0..aacc57aa90 100644 --- a/openstack/networking/v2/extensions/bgpvpns/testing/requests_test.go +++ b/openstack/networking/v2/extensions/bgpvpns/testing/requests_test.go @@ -35,7 +35,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListBGPVPNsResult) + fmt.Fprint(w, ListBGPVPNsResult) }) count := 0 @@ -67,7 +67,7 @@ func TestGet(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetBGPVPNResult) + fmt.Fprint(w, GetBGPVPNResult) }) r, err := bgpvpns.Get(context.TODO(), fake.ServiceClient(), bgpVpnID).Extract() @@ -87,7 +87,7 @@ func TestCreate(t *testing.T) { th.TestJSONRequest(t, r, CreateRequest) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreateResponse) + fmt.Fprint(w, CreateResponse) }) opts := bgpvpns.CreateOpts{ @@ -148,7 +148,7 @@ func TestUpdate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdateBGPVPNResponse) + fmt.Fprint(w, UpdateBGPVPNResponse) }) name := "foo" @@ -186,7 +186,7 @@ func TestListNetworkAssociations(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListNetworkAssociationsResult) + fmt.Fprint(w, ListNetworkAssociationsResult) }) count := 0 @@ -223,7 +223,7 @@ func TestCreateNetworkAssociation(t *testing.T) { th.TestJSONRequest(t, r, CreateNetworkAssociationRequest) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreateNetworkAssociationResponse) + fmt.Fprint(w, CreateNetworkAssociationResponse) }) opts := bgpvpns.CreateNetworkAssociationOpts{ @@ -245,7 +245,7 @@ func TestGetNetworkAssociation(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetNetworkAssociationResult) + fmt.Fprint(w, GetNetworkAssociationResult) }) r, err := bgpvpns.GetNetworkAssociation(context.TODO(), fake.ServiceClient(), bgpVpnID, networkAssociationID).Extract() @@ -289,7 +289,7 @@ func TestListRouterAssociations(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListRouterAssociationsResult) + fmt.Fprint(w, ListRouterAssociationsResult) }) count := 0 @@ -326,7 +326,7 @@ func TestCreateRouterAssociation(t *testing.T) { th.TestJSONRequest(t, r, CreateRouterAssociationRequest) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreateRouterAssociationResponse) + fmt.Fprint(w, CreateRouterAssociationResponse) }) opts := bgpvpns.CreateRouterAssociationOpts{ @@ -348,7 +348,7 @@ func TestGetRouterAssociation(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetRouterAssociationResult) + fmt.Fprint(w, GetRouterAssociationResult) }) r, err := bgpvpns.GetRouterAssociation(context.TODO(), fake.ServiceClient(), bgpVpnID, routerAssociationID).Extract() @@ -370,7 +370,7 @@ func TestUpdateRouterAssociation(t *testing.T) { th.TestJSONRequest(t, r, UpdateRouterAssociationRequest) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdateRouterAssociationResponse) + fmt.Fprint(w, UpdateRouterAssociationResponse) }) opts := bgpvpns.UpdateRouterAssociationOpts{ @@ -417,7 +417,7 @@ func TestListPortAssociations(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListPortAssociationsResult) + fmt.Fprint(w, ListPortAssociationsResult) }) count := 0 @@ -454,7 +454,7 @@ func TestCreatePortAssociation(t *testing.T) { th.TestJSONRequest(t, r, CreatePortAssociationRequest) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreatePortAssociationResponse) + fmt.Fprint(w, CreatePortAssociationResponse) }) opts := bgpvpns.CreatePortAssociationOpts{ @@ -476,7 +476,7 @@ func TestGetPortAssociation(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetPortAssociationResult) + fmt.Fprint(w, GetPortAssociationResult) }) r, err := bgpvpns.GetPortAssociation(context.TODO(), fake.ServiceClient(), bgpVpnID, portAssociationID).Extract() @@ -498,7 +498,7 @@ func TestUpdatePortAssociation(t *testing.T) { th.TestJSONRequest(t, r, UpdatePortAssociationRequest) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdatePortAssociationResponse) + fmt.Fprint(w, UpdatePortAssociationResponse) }) opts := bgpvpns.UpdatePortAssociationOpts{ diff --git a/openstack/networking/v2/extensions/dns/testing/fixtures_test.go b/openstack/networking/v2/extensions/dns/testing/fixtures_test.go index 340c90083c..85679382de 100644 --- a/openstack/networking/v2/extensions/dns/testing/fixtures_test.go +++ b/openstack/networking/v2/extensions/dns/testing/fixtures_test.go @@ -78,7 +78,7 @@ func PortHandleListSuccessfully(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, porttest.ListResponse) + fmt.Fprint(w, porttest.ListResponse) }) } @@ -90,7 +90,7 @@ func PortHandleGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, porttest.GetResponse) + fmt.Fprint(w, porttest.GetResponse) }) } @@ -121,7 +121,7 @@ func PortHandleCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "port": { "status": "DOWN", @@ -184,7 +184,7 @@ func PortHandleUpdate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "port": { "status": "DOWN", @@ -229,7 +229,7 @@ func FloatingIPHandleList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, floatingiptest.ListResponseDNS) + fmt.Fprint(w, floatingiptest.ListResponseDNS) }) } @@ -241,7 +241,7 @@ func FloatingIPHandleGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, fmt.Sprintf(`{"floatingip": %s}`, floatingiptest.FipDNS)) + fmt.Fprint(w, fmt.Sprintf(`{"floatingip": %s}`, floatingiptest.FipDNS)) }) } @@ -264,7 +264,7 @@ func FloatingIPHandleCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, fmt.Sprintf(`{"floatingip": %s}`, floatingiptest.FipDNS)) + fmt.Fprint(w, fmt.Sprintf(`{"floatingip": %s}`, floatingiptest.FipDNS)) }) } @@ -278,7 +278,7 @@ func NetworkHandleList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, networktest.ListResponse) + fmt.Fprint(w, networktest.ListResponse) }) } @@ -290,7 +290,7 @@ func NetworkHandleGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, networktest.GetResponse) + fmt.Fprint(w, networktest.GetResponse) }) } @@ -304,7 +304,7 @@ func NetworkHandleCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, NetworkCreateResponse) + fmt.Fprint(w, NetworkCreateResponse) }) } @@ -319,6 +319,6 @@ func NetworkHandleUpdate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, NetworkUpdateResponse) + fmt.Fprint(w, NetworkUpdateResponse) }) } diff --git a/openstack/networking/v2/extensions/external/testing/results_test.go b/openstack/networking/v2/extensions/external/testing/results_test.go index 12062e53d8..bf5c02d636 100644 --- a/openstack/networking/v2/extensions/external/testing/results_test.go +++ b/openstack/networking/v2/extensions/external/testing/results_test.go @@ -24,7 +24,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, nettest.ListResponse) + fmt.Fprint(w, nettest.ListResponse) }) type NetworkWithExternalExt struct { @@ -54,7 +54,7 @@ func TestGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, nettest.GetResponse) + fmt.Fprint(w, nettest.GetResponse) }) var s struct { @@ -83,7 +83,7 @@ func TestCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreateResponse) + fmt.Fprint(w, CreateResponse) }) iTrue := true @@ -118,7 +118,7 @@ func TestUpdate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdateResponse) + fmt.Fprint(w, UpdateResponse) }) iTrue := true diff --git a/openstack/networking/v2/extensions/fwaas_v2/groups/testing/requests_test.go b/openstack/networking/v2/extensions/fwaas_v2/groups/testing/requests_test.go index 59768a756d..540f80aaf4 100644 --- a/openstack/networking/v2/extensions/fwaas_v2/groups/testing/requests_test.go +++ b/openstack/networking/v2/extensions/fwaas_v2/groups/testing/requests_test.go @@ -23,7 +23,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "firewall_groups": [ { @@ -136,7 +136,7 @@ func TestGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "firewall_group": { "id": "6bfb0f10-07f7-4a40-b534-bad4b4ca3428", @@ -199,7 +199,7 @@ func TestCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "firewall_group": { "id": "6bfb0f10-07f7-4a40-b534-bad4b4ca3428", @@ -260,7 +260,7 @@ func TestUpdate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "firewall_group": { "id": "6bfb0f10-07f7-4a40-b534-bad4b4ca3428", @@ -319,7 +319,7 @@ func TestRemoveIngressPolicy(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "firewall_group": { "id": "6bfb0f10-07f7-4a40-b534-bad4b4ca3428", @@ -367,7 +367,7 @@ func TestRemoveEgressPolicy(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "firewall_group": { "id": "6bfb0f10-07f7-4a40-b534-bad4b4ca3428", diff --git a/openstack/networking/v2/extensions/fwaas_v2/policies/testing/requests_test.go b/openstack/networking/v2/extensions/fwaas_v2/policies/testing/requests_test.go index 3141f19795..217c062f4c 100644 --- a/openstack/networking/v2/extensions/fwaas_v2/policies/testing/requests_test.go +++ b/openstack/networking/v2/extensions/fwaas_v2/policies/testing/requests_test.go @@ -24,7 +24,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "firewall_policies": [ { @@ -135,7 +135,7 @@ func TestCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "firewall_policy":{ "name": "policy", @@ -189,7 +189,7 @@ func TestInsertRule(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "audited": false, "description": "TESTACC-DESC-8P12aLfW", @@ -252,7 +252,7 @@ func TestGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "firewall_policy":{ "name": "www", @@ -310,7 +310,7 @@ func TestUpdate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "firewall_policy":{ "name": "policy", @@ -377,7 +377,7 @@ func TestRemoveRule(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "audited": false, "description": "TESTACC-DESC-skno2e52", diff --git a/openstack/networking/v2/extensions/fwaas_v2/rules/testing/requests_test.go b/openstack/networking/v2/extensions/fwaas_v2/rules/testing/requests_test.go index 36469967d8..f251c563c0 100644 --- a/openstack/networking/v2/extensions/fwaas_v2/rules/testing/requests_test.go +++ b/openstack/networking/v2/extensions/fwaas_v2/rules/testing/requests_test.go @@ -24,7 +24,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "firewall_rules": [ { @@ -150,7 +150,7 @@ func TestCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "firewall_rule":{ "protocol": "tcp", @@ -215,7 +215,7 @@ func TestCreateAnyProtocol(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "firewall_rule":{ "protocol": null, @@ -264,7 +264,7 @@ func TestGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "firewall_rule":{ "protocol": "tcp", @@ -333,7 +333,7 @@ func TestUpdate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "firewall_rule":{ "protocol": "tcp", diff --git a/openstack/networking/v2/extensions/layer3/addressscopes/testing/requests_test.go b/openstack/networking/v2/extensions/layer3/addressscopes/testing/requests_test.go index b59bd3893d..815a0c0f08 100644 --- a/openstack/networking/v2/extensions/layer3/addressscopes/testing/requests_test.go +++ b/openstack/networking/v2/extensions/layer3/addressscopes/testing/requests_test.go @@ -23,7 +23,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, AddressScopesListResult) + fmt.Fprint(w, AddressScopesListResult) }) count := 0 @@ -63,7 +63,7 @@ func TestGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, AddressScopesGetResult) + fmt.Fprint(w, AddressScopesGetResult) }) s, err := addressscopes.Get(context.TODO(), fake.ServiceClient(), "9cc35860-522a-4d35-974d-51d4b011801e").Extract() @@ -91,7 +91,7 @@ func TestCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, AddressScopeCreateResult) + fmt.Fprint(w, AddressScopeCreateResult) }) opts := addressscopes.CreateOpts{ @@ -124,7 +124,7 @@ func TestUpdate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, AddressScopeUpdateResult) + fmt.Fprint(w, AddressScopeUpdateResult) }) shared := true diff --git a/openstack/networking/v2/extensions/layer3/extraroutes/testing/requests_test.go b/openstack/networking/v2/extensions/layer3/extraroutes/testing/requests_test.go index 66d08c8898..35d7516e1c 100644 --- a/openstack/networking/v2/extensions/layer3/extraroutes/testing/requests_test.go +++ b/openstack/networking/v2/extensions/layer3/extraroutes/testing/requests_test.go @@ -35,7 +35,7 @@ func TestAddExtraRoutes(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "router": { "name": "name", @@ -109,7 +109,7 @@ func TestRemoveExtraRoutes(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "router": { "name": "name", diff --git a/openstack/networking/v2/extensions/layer3/floatingips/testing/requests_test.go b/openstack/networking/v2/extensions/layer3/floatingips/testing/requests_test.go index 92830dabb4..40f5054b99 100644 --- a/openstack/networking/v2/extensions/layer3/floatingips/testing/requests_test.go +++ b/openstack/networking/v2/extensions/layer3/floatingips/testing/requests_test.go @@ -24,7 +24,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListResponse) + fmt.Fprint(w, ListResponse) }) count := 0 @@ -88,7 +88,7 @@ func TestInvalidNextPageURLs(t *testing.T) { th.Mux.HandleFunc("/v2.0/floatingips", func(w http.ResponseWriter, r *http.Request) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, `{"floatingips": [{}], "floatingips_links": {}}`) + fmt.Fprint(w, `{"floatingips": [{}], "floatingips_links": {}}`) }) err := floatingips.List(fake.ServiceClient(), floatingips.ListOpts{}).EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) { @@ -134,7 +134,7 @@ func TestCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "floatingip": { "router_id": "d23abc8d-2991-4a55-ba98-2aaea84cc72f", @@ -189,7 +189,7 @@ func TestCreateEmptyPort(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "floatingip": { "router_id": "d23abc8d-2991-4a55-ba98-2aaea84cc72f", @@ -243,7 +243,7 @@ func TestCreateWithSubnetID(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "floatingip": { "router_id": null, @@ -289,7 +289,7 @@ func TestGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "floatingip": { "floating_network_id": "90f742b1-6d17-487b-ba95-71881dbc0b64", @@ -342,7 +342,7 @@ func TestAssociate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "floatingip": { "router_id": "d23abc8d-2991-4a55-ba98-2aaea84cc72f", @@ -384,7 +384,7 @@ func TestDisassociate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "floatingip": { "router_id": "d23abc8d-2991-4a55-ba98-2aaea84cc72f", diff --git a/openstack/networking/v2/extensions/layer3/portforwarding/testing/requests_test.go b/openstack/networking/v2/extensions/layer3/portforwarding/testing/requests_test.go index c4ad108146..dc2aa8c49b 100644 --- a/openstack/networking/v2/extensions/layer3/portforwarding/testing/requests_test.go +++ b/openstack/networking/v2/extensions/layer3/portforwarding/testing/requests_test.go @@ -23,7 +23,7 @@ func TestPortForwardingList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListResponse) + fmt.Fprint(w, ListResponse) }) count := 0 @@ -91,7 +91,7 @@ func TestCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "port_forwarding": { "protocol": "tcp", @@ -134,7 +134,7 @@ func TestGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "port_forwarding": { "protocol": "tcp", @@ -196,7 +196,7 @@ func TestUpdate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "port_forwarding": { "protocol": "udp", diff --git a/openstack/networking/v2/extensions/layer3/routers/testing/requests_test.go b/openstack/networking/v2/extensions/layer3/routers/testing/requests_test.go index 541dd656b5..6ff1242366 100644 --- a/openstack/networking/v2/extensions/layer3/routers/testing/requests_test.go +++ b/openstack/networking/v2/extensions/layer3/routers/testing/requests_test.go @@ -24,7 +24,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "routers": [ { @@ -156,7 +156,7 @@ func TestCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "router": { "status": "ACTIVE", @@ -224,7 +224,7 @@ func TestGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "router": { "status": "ACTIVE", @@ -301,7 +301,7 @@ func TestUpdate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "router": { "status": "ACTIVE", @@ -367,7 +367,7 @@ func TestUpdateWithoutRoutes(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "router": { "status": "ACTIVE", @@ -422,7 +422,7 @@ func TestAllRoutesRemoved(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "router": { "status": "ACTIVE", @@ -481,7 +481,7 @@ func TestAddInterface(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "subnet_id": "0d32a837-8069-4ec3-84c4-3eef3e10b188", "tenant_id": "017d8de156df4177889f31a9bd6edc00", @@ -530,7 +530,7 @@ func TestRemoveInterface(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "subnet_id": "0d32a837-8069-4ec3-84c4-3eef3e10b188", "tenant_id": "017d8de156df4177889f31a9bd6edc00", @@ -561,7 +561,7 @@ func TestListL3Agents(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "agents": [ { diff --git a/openstack/networking/v2/extensions/mtu/testing/results_test.go b/openstack/networking/v2/extensions/mtu/testing/results_test.go index 273bdb5166..916bbc00f8 100644 --- a/openstack/networking/v2/extensions/mtu/testing/results_test.go +++ b/openstack/networking/v2/extensions/mtu/testing/results_test.go @@ -29,7 +29,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, nettest.ListResponse) + fmt.Fprint(w, nettest.ListResponse) }) type NetworkWithMTUExt struct { @@ -59,7 +59,7 @@ func TestGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, nettest.GetResponse) + fmt.Fprint(w, nettest.GetResponse) }) var s NetworkMTU @@ -85,7 +85,7 @@ func TestCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreateResponse) + fmt.Fprint(w, CreateResponse) }) iTrue := true @@ -123,7 +123,7 @@ func TestUpdate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdateResponse) + fmt.Fprint(w, UpdateResponse) }) iTrue := true diff --git a/openstack/networking/v2/extensions/networkipavailabilities/testing/requests_test.go b/openstack/networking/v2/extensions/networkipavailabilities/testing/requests_test.go index 86166b5e33..cdd6d8d4e2 100644 --- a/openstack/networking/v2/extensions/networkipavailabilities/testing/requests_test.go +++ b/openstack/networking/v2/extensions/networkipavailabilities/testing/requests_test.go @@ -24,7 +24,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, NetworkIPAvailabilityListResult) + fmt.Fprint(w, NetworkIPAvailabilityListResult) }) count := 0 @@ -65,7 +65,7 @@ func TestGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, NetworkIPAvailabilityGetResult) + fmt.Fprint(w, NetworkIPAvailabilityGetResult) }) s, err := networkipavailabilities.Get(context.TODO(), fake.ServiceClient(), "cf11ab78-2302-49fa-870f-851a08c7afb8").Extract() diff --git a/openstack/networking/v2/extensions/portsbinding/testing/fixtures_test.go b/openstack/networking/v2/extensions/portsbinding/testing/fixtures_test.go index 494fe49091..44e2b5db9b 100644 --- a/openstack/networking/v2/extensions/portsbinding/testing/fixtures_test.go +++ b/openstack/networking/v2/extensions/portsbinding/testing/fixtures_test.go @@ -18,7 +18,7 @@ func HandleListSuccessfully(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, porttest.ListResponse) + fmt.Fprint(w, porttest.ListResponse) }) } @@ -30,7 +30,7 @@ func HandleGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, porttest.GetResponse) + fmt.Fprint(w, porttest.GetResponse) }) } @@ -62,7 +62,7 @@ func HandleCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "port": { "status": "DOWN", @@ -120,7 +120,7 @@ func HandleUpdate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "port": { "status": "DOWN", diff --git a/openstack/networking/v2/extensions/provider/testing/results_test.go b/openstack/networking/v2/extensions/provider/testing/results_test.go index 4e21481de1..acbf9f7a1f 100644 --- a/openstack/networking/v2/extensions/provider/testing/results_test.go +++ b/openstack/networking/v2/extensions/provider/testing/results_test.go @@ -25,7 +25,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, nettest.ListResponse) + fmt.Fprint(w, nettest.ListResponse) }) type NetworkWithExt struct { @@ -60,7 +60,7 @@ func TestGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, nettest.GetResponse) + fmt.Fprint(w, nettest.GetResponse) }) var s struct { @@ -91,7 +91,7 @@ func TestCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, nettest.CreateResponse) + fmt.Fprint(w, nettest.CreateResponse) }) var s struct { @@ -142,7 +142,7 @@ func TestCreateWithMultipleProvider(t *testing.T) { `) w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "network": { "status": "ACTIVE", @@ -227,7 +227,7 @@ func TestUpdate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, nettest.UpdateResponse) + fmt.Fprint(w, nettest.UpdateResponse) }) var s struct { diff --git a/openstack/networking/v2/extensions/qos/policies/testing/requests_test.go b/openstack/networking/v2/extensions/qos/policies/testing/requests_test.go index 72b17e5330..4ad4cf3088 100644 --- a/openstack/networking/v2/extensions/qos/policies/testing/requests_test.go +++ b/openstack/networking/v2/extensions/qos/policies/testing/requests_test.go @@ -26,7 +26,7 @@ func TestGetPort(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - _, err := fmt.Fprintf(w, GetPortResponse) + _, err := fmt.Fprint(w, GetPortResponse) th.AssertNoErr(t, err) }) @@ -55,7 +55,7 @@ func TestCreatePort(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - _, err := fmt.Fprintf(w, CreatePortResponse) + _, err := fmt.Fprint(w, CreatePortResponse) th.AssertNoErr(t, err) }) @@ -93,7 +93,7 @@ func TestUpdatePortWithPolicy(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - _, err := fmt.Fprintf(w, UpdatePortWithPolicyResponse) + _, err := fmt.Fprint(w, UpdatePortWithPolicyResponse) th.AssertNoErr(t, err) }) @@ -131,7 +131,7 @@ func TestUpdatePortWithoutPolicy(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - _, err := fmt.Fprintf(w, UpdatePortWithoutPolicyResponse) + _, err := fmt.Fprint(w, UpdatePortWithoutPolicyResponse) th.AssertNoErr(t, err) }) @@ -166,7 +166,7 @@ func TestGetNetwork(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - _, err := fmt.Fprintf(w, GetNetworkResponse) + _, err := fmt.Fprint(w, GetNetworkResponse) th.AssertNoErr(t, err) }) @@ -195,7 +195,7 @@ func TestCreateNetwork(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - _, err := fmt.Fprintf(w, CreateNetworkResponse) + _, err := fmt.Fprint(w, CreateNetworkResponse) th.AssertNoErr(t, err) }) @@ -232,7 +232,7 @@ func TestUpdateNetworkWithPolicy(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - _, err := fmt.Fprintf(w, UpdateNetworkWithPolicyResponse) + _, err := fmt.Fprint(w, UpdateNetworkWithPolicyResponse) th.AssertNoErr(t, err) }) @@ -273,7 +273,7 @@ func TestUpdateNetworkWithoutPolicy(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - _, err := fmt.Fprintf(w, UpdateNetworkWithoutPolicyResponse) + _, err := fmt.Fprint(w, UpdateNetworkWithoutPolicyResponse) th.AssertNoErr(t, err) }) @@ -307,7 +307,7 @@ func TestListPolicies(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListPoliciesResponse) + fmt.Fprint(w, ListPoliciesResponse) }) count := 0 @@ -347,7 +347,7 @@ func TestGetPolicy(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetPolicyResponse) + fmt.Fprint(w, GetPolicyResponse) }) p, err := policies.Get(context.TODO(), fake.ServiceClient(), "30a57f4a-336b-4382-8275-d708babd2241").Extract() @@ -387,7 +387,7 @@ func TestCreatePolicy(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreatePolicyResponse) + fmt.Fprint(w, CreatePolicyResponse) }) opts := policies.CreateOpts{ @@ -425,7 +425,7 @@ func TestUpdatePolicy(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdatePolicyResponse) + fmt.Fprint(w, UpdatePolicyResponse) }) shared := true diff --git a/openstack/networking/v2/extensions/qos/rules/testing/requests_test.go b/openstack/networking/v2/extensions/qos/rules/testing/requests_test.go index 4ee49605ea..20de755132 100644 --- a/openstack/networking/v2/extensions/qos/rules/testing/requests_test.go +++ b/openstack/networking/v2/extensions/qos/rules/testing/requests_test.go @@ -23,7 +23,7 @@ func TestListBandwidthLimitRule(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, BandwidthLimitRulesListResult) + fmt.Fprint(w, BandwidthLimitRulesListResult) }) count := 0 @@ -71,7 +71,7 @@ func TestGetBandwidthLimitRule(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, BandwidthLimitRulesGetResult) + fmt.Fprint(w, BandwidthLimitRulesGetResult) }) r, err := rules.GetBandwidthLimitRule(context.TODO(), fake.ServiceClient(), "501005fa-3b56-4061-aaca-3f24995112e1", "30a57f4a-336b-4382-8275-d708babd2241").ExtractBandwidthLimitRule() @@ -97,7 +97,7 @@ func TestCreateBandwidthLimitRule(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, BandwidthLimitRulesCreateResult) + fmt.Fprint(w, BandwidthLimitRulesCreateResult) }) opts := rules.CreateBandwidthLimitRuleOpts{ @@ -125,7 +125,7 @@ func TestUpdateBandwidthLimitRule(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, BandwidthLimitRulesUpdateResult) + fmt.Fprint(w, BandwidthLimitRulesUpdateResult) }) maxKBps := 500 @@ -166,7 +166,7 @@ func TestListDSCPMarkingRule(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, DSCPMarkingRulesListResult) + fmt.Fprint(w, DSCPMarkingRulesListResult) }) count := 0 @@ -212,7 +212,7 @@ func TestGetDSCPMarkingRule(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, DSCPMarkingRuleGetResult) + fmt.Fprint(w, DSCPMarkingRuleGetResult) }) r, err := rules.GetDSCPMarkingRule(context.TODO(), fake.ServiceClient(), "501005fa-3b56-4061-aaca-3f24995112e1", "30a57f4a-336b-4382-8275-d708babd2241").ExtractDSCPMarkingRule() @@ -236,7 +236,7 @@ func TestCreateDSCPMarkingRule(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, DSCPMarkingRuleCreateResult) + fmt.Fprint(w, DSCPMarkingRuleCreateResult) }) opts := rules.CreateDSCPMarkingRuleOpts{ @@ -263,7 +263,7 @@ func TestUpdateDSCPMarkingRule(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, DSCPMarkingRuleUpdateResult) + fmt.Fprint(w, DSCPMarkingRuleUpdateResult) }) dscpMark := 26 @@ -302,7 +302,7 @@ func TestListMinimumBandwidthRule(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, MinimumBandwidthRulesListResult) + fmt.Fprint(w, MinimumBandwidthRulesListResult) }) count := 0 @@ -349,7 +349,7 @@ func TestGetMinimumBandwidthRule(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, MinimumBandwidthRulesGetResult) + fmt.Fprint(w, MinimumBandwidthRulesGetResult) }) r, err := rules.GetMinimumBandwidthRule(context.TODO(), fake.ServiceClient(), "501005fa-3b56-4061-aaca-3f24995112e1", "30a57f4a-336b-4382-8275-d708babd2241").ExtractMinimumBandwidthRule() @@ -374,7 +374,7 @@ func TestCreateMinimumBandwidthRule(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, MinimumBandwidthRulesCreateResult) + fmt.Fprint(w, MinimumBandwidthRulesCreateResult) }) opts := rules.CreateMinimumBandwidthRuleOpts{ @@ -400,7 +400,7 @@ func TestUpdateMinimumBandwidthRule(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, MinimumBandwidthRulesUpdateResult) + fmt.Fprint(w, MinimumBandwidthRulesUpdateResult) }) minKBps := 500 diff --git a/openstack/networking/v2/extensions/qos/ruletypes/testing/requests_test.go b/openstack/networking/v2/extensions/qos/ruletypes/testing/requests_test.go index 74eeb49aa4..7bea9f6b66 100644 --- a/openstack/networking/v2/extensions/qos/ruletypes/testing/requests_test.go +++ b/openstack/networking/v2/extensions/qos/ruletypes/testing/requests_test.go @@ -52,7 +52,7 @@ func TestGetRuleType(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - _, err := fmt.Fprintf(w, GetRuleTypeResponse) + _, err := fmt.Fprint(w, GetRuleTypeResponse) th.AssertNoErr(t, err) }) diff --git a/openstack/networking/v2/extensions/quotas/testing/requests_test.go b/openstack/networking/v2/extensions/quotas/testing/requests_test.go index 7ed3100242..a5714d17fe 100644 --- a/openstack/networking/v2/extensions/quotas/testing/requests_test.go +++ b/openstack/networking/v2/extensions/quotas/testing/requests_test.go @@ -23,7 +23,7 @@ func TestGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetResponseRaw) + fmt.Fprint(w, GetResponseRaw) }) q, err := quotas.Get(context.TODO(), fake.ServiceClient(), "0a73845280574ad389c292f6a74afa76").Extract() @@ -42,7 +42,7 @@ func TestGetDetail(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetDetailedResponseRaw) + fmt.Fprint(w, GetDetailedResponseRaw) }) q, err := quotas.GetDetail(context.TODO(), fake.ServiceClient(), "0a73845280574ad389c292f6a74afa76").Extract() @@ -61,7 +61,7 @@ func TestUpdate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdateRequestResponseRaw) + fmt.Fprint(w, UpdateRequestResponseRaw) }) q, err := quotas.Update(context.TODO(), fake.ServiceClient(), "0a73845280574ad389c292f6a74afa76", quotas.UpdateOpts{ diff --git a/openstack/networking/v2/extensions/rbacpolicies/testing/requests_test.go b/openstack/networking/v2/extensions/rbacpolicies/testing/requests_test.go index 7503bc7a74..9fc04412f4 100644 --- a/openstack/networking/v2/extensions/rbacpolicies/testing/requests_test.go +++ b/openstack/networking/v2/extensions/rbacpolicies/testing/requests_test.go @@ -25,7 +25,7 @@ func TestCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreateResponse) + fmt.Fprint(w, CreateResponse) }) options := rbacpolicies.CreateOpts{ @@ -51,7 +51,7 @@ func TestGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetResponse) + fmt.Fprint(w, GetResponse) }) n, err := rbacpolicies.Get(context.TODO(), fake.ServiceClient(), "2cf7523a-93b5-4e69-9360-6c6bf986bb7c").Extract() @@ -70,7 +70,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListResponse) + fmt.Fprint(w, ListResponse) }) client := fake.ServiceClient() @@ -106,7 +106,7 @@ func TestListWithAllPages(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListResponse) + fmt.Fprint(w, ListResponse) }) client := fake.ServiceClient() @@ -159,7 +159,7 @@ func TestUpdate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdateResponse) + fmt.Fprint(w, UpdateResponse) }) options := rbacpolicies.UpdateOpts{TargetTenant: "9d766060b6354c9e8e2da44cab0e8f38"} diff --git a/openstack/networking/v2/extensions/security/groups/testing/requests_test.go b/openstack/networking/v2/extensions/security/groups/testing/requests_test.go index 30c3ab6359..f816f0d6d2 100644 --- a/openstack/networking/v2/extensions/security/groups/testing/requests_test.go +++ b/openstack/networking/v2/extensions/security/groups/testing/requests_test.go @@ -24,7 +24,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, SecurityGroupListResponse) + fmt.Fprint(w, SecurityGroupListResponse) }) count := 0 @@ -64,7 +64,7 @@ func TestCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, SecurityGroupCreateResponse) + fmt.Fprint(w, SecurityGroupCreateResponse) }) opts := groups.CreateOpts{Name: "new-webservers", Description: "security group for webservers"} @@ -87,7 +87,7 @@ func TestUpdate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, SecurityGroupUpdateResponse) + fmt.Fprint(w, SecurityGroupUpdateResponse) }) opts := groups.UpdateOpts{Name: "newer-webservers"} @@ -112,7 +112,7 @@ func TestGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, SecurityGroupGetResponse) + fmt.Fprint(w, SecurityGroupGetResponse) }) sg, err := groups.Get(context.TODO(), fake.ServiceClient(), "85cc3048-abc3-43cc-89b3-377341426ac5").Extract() diff --git a/openstack/networking/v2/extensions/security/rules/testing/requests_test.go b/openstack/networking/v2/extensions/security/rules/testing/requests_test.go index 40372c298a..843d7eb202 100644 --- a/openstack/networking/v2/extensions/security/rules/testing/requests_test.go +++ b/openstack/networking/v2/extensions/security/rules/testing/requests_test.go @@ -23,7 +23,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "security_group_rules": [ { @@ -131,7 +131,7 @@ func TestCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "security_group_rule": { "description": "test description of rule", @@ -190,7 +190,7 @@ func TestCreateAnyProtocol(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "security_group_rule": { "description": "test description of rule", @@ -252,7 +252,7 @@ func TestGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "security_group_rule": { "direction": "egress", diff --git a/openstack/networking/v2/extensions/subnetpools/testing/requests_test.go b/openstack/networking/v2/extensions/subnetpools/testing/requests_test.go index 50f479b9d1..2d8df70180 100644 --- a/openstack/networking/v2/extensions/subnetpools/testing/requests_test.go +++ b/openstack/networking/v2/extensions/subnetpools/testing/requests_test.go @@ -24,7 +24,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, SubnetPoolsListResult) + fmt.Fprint(w, SubnetPoolsListResult) }) count := 0 @@ -66,7 +66,7 @@ func TestGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, SubnetPoolGetResult) + fmt.Fprint(w, SubnetPoolGetResult) }) s, err := subnetpools.Get(context.TODO(), fake.ServiceClient(), "0a738452-8057-4ad3-89c2-92f6a74afa76").Extract() @@ -106,7 +106,7 @@ func TestCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, SubnetPoolCreateResult) + fmt.Fprint(w, SubnetPoolCreateResult) }) opts := subnetpools.CreateOpts{ @@ -148,7 +148,7 @@ func TestUpdate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, SubnetPoolUpdateResponse) + fmt.Fprint(w, SubnetPoolUpdateResponse) }) nullString := "" diff --git a/openstack/networking/v2/extensions/testing/delegate_test.go b/openstack/networking/v2/extensions/testing/delegate_test.go index eb130cd4b0..9f3421f272 100644 --- a/openstack/networking/v2/extensions/testing/delegate_test.go +++ b/openstack/networking/v2/extensions/testing/delegate_test.go @@ -23,7 +23,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "extensions": [ { @@ -83,7 +83,7 @@ func TestGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "extension": { "updated": "2013-02-03T10:00:00-00:00", diff --git a/openstack/networking/v2/extensions/trunks/testing/requests_test.go b/openstack/networking/v2/extensions/trunks/testing/requests_test.go index bc4a2341ab..81e6bef8c2 100644 --- a/openstack/networking/v2/extensions/trunks/testing/requests_test.go +++ b/openstack/networking/v2/extensions/trunks/testing/requests_test.go @@ -25,7 +25,7 @@ func TestCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreateResponse) + fmt.Fprint(w, CreateResponse) }) iTrue := true @@ -73,7 +73,7 @@ func TestCreateNoSubports(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreateNoSubportsResponse) + fmt.Fprint(w, CreateNoSubportsResponse) }) iTrue := true @@ -115,7 +115,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListResponse) + fmt.Fprint(w, ListResponse) }) client := fake.ServiceClient() @@ -153,7 +153,7 @@ func TestGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetResponse) + fmt.Fprint(w, GetResponse) }) n, err := trunks.Get(context.TODO(), fake.ServiceClient(), "f6a9718c-5a64-43e3-944f-4deccad8e78c").Extract() @@ -177,7 +177,7 @@ func TestUpdate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdateResponse) + fmt.Fprint(w, UpdateResponse) }) iFalse := false @@ -207,7 +207,7 @@ func TestGetSubports(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListSubportsResponse) + fmt.Fprint(w, ListSubportsResponse) }) client := fake.ServiceClient() @@ -259,7 +259,7 @@ func TestAddSubports(t *testing.T) { th.TestJSONRequest(t, r, AddSubportsRequest) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, AddSubportsResponse) + fmt.Fprint(w, AddSubportsResponse) }) client := fake.ServiceClient() @@ -287,7 +287,7 @@ func TestRemoveSubports(t *testing.T) { th.TestJSONRequest(t, r, RemoveSubportsRequest) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, RemoveSubportsResponse) + fmt.Fprint(w, RemoveSubportsResponse) }) client := fake.ServiceClient() diff --git a/openstack/networking/v2/extensions/vlantransparent/testing/requests_test.go b/openstack/networking/v2/extensions/vlantransparent/testing/requests_test.go index d298894de7..dc5d55043a 100644 --- a/openstack/networking/v2/extensions/vlantransparent/testing/requests_test.go +++ b/openstack/networking/v2/extensions/vlantransparent/testing/requests_test.go @@ -23,7 +23,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, NetworksVLANTransparentListResult) + fmt.Fprint(w, NetworksVLANTransparentListResult) }) type networkVLANTransparentExt struct { @@ -59,7 +59,7 @@ func TestGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, NetworksVLANTransparentGetResult) + fmt.Fprint(w, NetworksVLANTransparentGetResult) }) var s struct { @@ -94,7 +94,7 @@ func TestCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, NetworksVLANTransparentCreateResult) + fmt.Fprint(w, NetworksVLANTransparentCreateResult) }) iTrue := true @@ -139,7 +139,7 @@ func TestUpdate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, NetworksVLANTransparentUpdateResult) + fmt.Fprint(w, NetworksVLANTransparentUpdateResult) }) iFalse := false diff --git a/openstack/networking/v2/extensions/vpnaas/endpointgroups/testing/requests_test.go b/openstack/networking/v2/extensions/vpnaas/endpointgroups/testing/requests_test.go index 806580dd4e..dbf3ba515e 100644 --- a/openstack/networking/v2/extensions/vpnaas/endpointgroups/testing/requests_test.go +++ b/openstack/networking/v2/extensions/vpnaas/endpointgroups/testing/requests_test.go @@ -36,7 +36,7 @@ func TestCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "endpoint_group": { "description": "", @@ -90,7 +90,7 @@ func TestGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "endpoint_group": { "description": "", @@ -135,7 +135,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "endpoint_groups": [ { @@ -224,7 +224,7 @@ func TestUpdate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "endpoint_group": { "description": "updated description", diff --git a/openstack/networking/v2/extensions/vpnaas/ikepolicies/testing/requests_test.go b/openstack/networking/v2/extensions/vpnaas/ikepolicies/testing/requests_test.go index 74b9427cc1..e8e63dfde7 100644 --- a/openstack/networking/v2/extensions/vpnaas/ikepolicies/testing/requests_test.go +++ b/openstack/networking/v2/extensions/vpnaas/ikepolicies/testing/requests_test.go @@ -35,7 +35,7 @@ func TestCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "ikepolicy":{ "name": "policy", @@ -97,7 +97,7 @@ func TestGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "ikepolicy":{ "name": "policy", @@ -165,7 +165,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "ikepolicies": [ { @@ -253,7 +253,7 @@ func TestUpdate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "ikepolicy": { "name": "updatedname", diff --git a/openstack/networking/v2/extensions/vpnaas/ipsecpolicies/testing/requests_test.go b/openstack/networking/v2/extensions/vpnaas/ipsecpolicies/testing/requests_test.go index 0363c7c63e..35c09a4ad5 100644 --- a/openstack/networking/v2/extensions/vpnaas/ipsecpolicies/testing/requests_test.go +++ b/openstack/networking/v2/extensions/vpnaas/ipsecpolicies/testing/requests_test.go @@ -41,7 +41,7 @@ func TestCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "ipsecpolicy": { "name": "ipsecpolicy1", @@ -111,7 +111,7 @@ func TestGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "ipsecpolicy": { "name": "ipsecpolicy1", @@ -180,7 +180,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "ipsecpolicies": [ { @@ -268,7 +268,7 @@ func TestUpdate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "ipsecpolicy": { diff --git a/openstack/networking/v2/extensions/vpnaas/services/testing/requests_test.go b/openstack/networking/v2/extensions/vpnaas/services/testing/requests_test.go index ce9e50171e..c0a33e8d0f 100644 --- a/openstack/networking/v2/extensions/vpnaas/services/testing/requests_test.go +++ b/openstack/networking/v2/extensions/vpnaas/services/testing/requests_test.go @@ -36,7 +36,7 @@ func TestCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "vpnservice": { "router_id": "66e3b16c-8ce5-40fb-bb49-ab6d8dc3f2aa", @@ -91,7 +91,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "vpnservices":[ { @@ -154,7 +154,7 @@ func TestGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "vpnservice": { "router_id": "66e3b16c-8ce5-40fb-bb49-ab6d8dc3f2aa", @@ -223,7 +223,7 @@ func TestUpdate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "vpnservice": { "router_id": "66e3b16c-8ce5-40fb-bb49-ab6d8dc3f2aa", diff --git a/openstack/networking/v2/extensions/vpnaas/siteconnections/testing/requests_test.go b/openstack/networking/v2/extensions/vpnaas/siteconnections/testing/requests_test.go index 68977acee4..58279b75d5 100644 --- a/openstack/networking/v2/extensions/vpnaas/siteconnections/testing/requests_test.go +++ b/openstack/networking/v2/extensions/vpnaas/siteconnections/testing/requests_test.go @@ -45,7 +45,7 @@ func TestCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "ipsec_site_connection": { "status": "PENDING_CREATE", @@ -150,7 +150,7 @@ func TestGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "ipsec_site_connection": { "status": "PENDING_CREATE", @@ -227,7 +227,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "ipsec_site_connections":[ { @@ -336,7 +336,7 @@ func TestUpdate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "ipsec_site_connection": { diff --git a/openstack/networking/v2/networks/testing/requests_test.go b/openstack/networking/v2/networks/testing/requests_test.go index c28dd2ed0f..f4e905a64f 100644 --- a/openstack/networking/v2/networks/testing/requests_test.go +++ b/openstack/networking/v2/networks/testing/requests_test.go @@ -25,7 +25,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListResponse) + fmt.Fprint(w, ListResponse) }) client := fake.ServiceClient() @@ -62,7 +62,7 @@ func TestListWithExtensions(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListResponse) + fmt.Fprint(w, ListResponse) }) client := fake.ServiceClient() @@ -101,7 +101,7 @@ func TestGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetResponse) + fmt.Fprint(w, GetResponse) }) n, err := networks.Get(context.TODO(), fake.ServiceClient(), "d32019d3-bc6e-4319-9c1d-6722fc136a22").Extract() @@ -122,7 +122,7 @@ func TestGetWithExtensions(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetResponse) + fmt.Fprint(w, GetResponse) }) var networkWithExtensions struct { @@ -150,7 +150,7 @@ func TestCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreateResponse) + fmt.Fprint(w, CreateResponse) }) iTrue := true @@ -176,7 +176,7 @@ func TestCreateWithOptionalFields(t *testing.T) { th.TestJSONRequest(t, r, CreateOptionalFieldsRequest) w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, `{}`) + fmt.Fprint(w, `{}`) }) iTrue := true @@ -205,7 +205,7 @@ func TestUpdate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdateResponse) + fmt.Fprint(w, UpdateResponse) }) iTrue, iFalse := true, false @@ -237,7 +237,7 @@ func TestUpdateRevision(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdateResponse) + fmt.Fprint(w, UpdateResponse) }) th.Mux.HandleFunc("/v2.0/networks/4e8e5957-649f-477b-9e5b-f1f75b21c03d", func(w http.ResponseWriter, r *http.Request) { @@ -251,7 +251,7 @@ func TestUpdateRevision(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdateResponse) + fmt.Fprint(w, UpdateResponse) }) iTrue, iFalse := true, false @@ -293,7 +293,7 @@ func TestCreatePortSecurity(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreatePortSecurityResponse) + fmt.Fprint(w, CreatePortSecurityResponse) }) var networkWithExtensions struct { @@ -330,7 +330,7 @@ func TestUpdatePortSecurity(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdatePortSecurityResponse) + fmt.Fprint(w, UpdatePortSecurityResponse) }) var networkWithExtensions struct { diff --git a/openstack/networking/v2/ports/testing/requests_test.go b/openstack/networking/v2/ports/testing/requests_test.go index 7c3569b70b..1b77780610 100644 --- a/openstack/networking/v2/ports/testing/requests_test.go +++ b/openstack/networking/v2/ports/testing/requests_test.go @@ -27,7 +27,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListResponse) + fmt.Fprint(w, ListResponse) }) count := 0 @@ -86,7 +86,7 @@ func TestListWithExtensions(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListResponse) + fmt.Fprint(w, ListResponse) }) type portWithExt struct { @@ -117,7 +117,7 @@ func TestGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetResponse) + fmt.Fprint(w, GetResponse) }) n, err := ports.Get(context.TODO(), fake.ServiceClient(), "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2").Extract() @@ -152,7 +152,7 @@ func TestGetWithExtensions(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetResponse) + fmt.Fprint(w, GetResponse) }) var portWithExtensions struct { @@ -181,7 +181,7 @@ func TestCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreateResponse) + fmt.Fprint(w, CreateResponse) }) asu := true @@ -231,7 +231,7 @@ func TestCreateOmitSecurityGroups(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreateOmitSecurityGroupsResponse) + fmt.Fprint(w, CreateOmitSecurityGroupsResponse) }) asu := true @@ -280,7 +280,7 @@ func TestCreateWithNoSecurityGroup(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreateWithNoSecurityGroupsResponse) + fmt.Fprint(w, CreateWithNoSecurityGroupsResponse) }) asu := true @@ -329,7 +329,7 @@ func TestCreateWithPropagateUplinkStatus(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreatePropagateUplinkStatusResponse) + fmt.Fprint(w, CreatePropagateUplinkStatusResponse) }) asu := true @@ -374,7 +374,7 @@ func TestCreateWithValueSpecs(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreateValueSpecResponse) + fmt.Fprint(w, CreateValueSpecResponse) }) asu := true @@ -427,7 +427,7 @@ func TestCreateWithInvalidValueSpecs(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreateValueSpecResponse) + fmt.Fprint(w, CreateValueSpecResponse) }) asu := true @@ -483,7 +483,7 @@ func TestCreatePortSecurity(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreatePortSecurityResponse) + fmt.Fprint(w, CreatePortSecurityResponse) }) var portWithExt struct { @@ -531,7 +531,7 @@ func TestUpdate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdateResponse) + fmt.Fprint(w, UpdateResponse) }) name := "new_port_name" @@ -573,7 +573,7 @@ func TestUpdateOmitSecurityGroups(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdateOmitSecurityGroupsResponse) + fmt.Fprint(w, UpdateOmitSecurityGroupsResponse) }) name := "new_port_name" @@ -614,7 +614,7 @@ func TestUpdatePropagateUplinkStatus(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdatePropagateUplinkStatusResponse) + fmt.Fprint(w, UpdatePropagateUplinkStatusResponse) }) propagateUplinkStatus := true @@ -642,7 +642,7 @@ func TestUpdateValueSpecs(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdateValueSpecsResponse) + fmt.Fprint(w, UpdateValueSpecsResponse) }) options := ports.UpdateOpts{ @@ -669,7 +669,7 @@ func TestUpdatePortSecurity(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdatePortSecurityResponse) + fmt.Fprint(w, UpdatePortSecurityResponse) }) var portWithExt struct { @@ -707,7 +707,7 @@ func TestUpdateRevision(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdateResponse) + fmt.Fprint(w, UpdateResponse) }) th.Mux.HandleFunc("/v2.0/ports/65c0ee9f-d634-4522-8954-51021b570b0e", func(w http.ResponseWriter, r *http.Request) { th.TestMethod(t, r, "PUT") @@ -720,7 +720,7 @@ func TestUpdateRevision(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdateResponse) + fmt.Fprint(w, UpdateResponse) }) name := "new_port_name" @@ -757,7 +757,7 @@ func TestRemoveSecurityGroups(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, RemoveSecurityGroupResponse) + fmt.Fprint(w, RemoveSecurityGroupResponse) }) name := "new_port_name" @@ -799,7 +799,7 @@ func TestRemoveAllowedAddressPairs(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, RemoveAllowedAddressPairsResponse) + fmt.Fprint(w, RemoveAllowedAddressPairsResponse) }) name := "new_port_name" @@ -837,7 +837,7 @@ func TestDontUpdateAllowedAddressPairs(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, DontUpdateAllowedAddressPairsResponse) + fmt.Fprint(w, DontUpdateAllowedAddressPairsResponse) }) name := "new_port_name" @@ -887,7 +887,7 @@ func TestGetWithExtraDHCPOpts(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetWithExtraDHCPOptsResponse) + fmt.Fprint(w, GetWithExtraDHCPOptsResponse) }) var s struct { @@ -933,7 +933,7 @@ func TestCreateWithExtraDHCPOpts(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, CreateWithExtraDHCPOptsResponse) + fmt.Fprint(w, CreateWithExtraDHCPOptsResponse) }) adminStateUp := true @@ -996,7 +996,7 @@ func TestUpdateWithExtraDHCPOpts(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UpdateWithExtraDHCPOptsResponse) + fmt.Fprint(w, UpdateWithExtraDHCPOptsResponse) }) name := "updated-port-with-dhcp-opts" diff --git a/openstack/networking/v2/subnets/testing/requests_test.go b/openstack/networking/v2/subnets/testing/requests_test.go index 1df6fd1ce3..41ec607cd8 100644 --- a/openstack/networking/v2/subnets/testing/requests_test.go +++ b/openstack/networking/v2/subnets/testing/requests_test.go @@ -23,7 +23,7 @@ func TestList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, SubnetListResult) + fmt.Fprint(w, SubnetListResult) }) count := 0 @@ -65,7 +65,7 @@ func TestGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, SubnetGetResult) + fmt.Fprint(w, SubnetGetResult) }) s, err := subnets.Get(context.TODO(), fake.ServiceClient(), "54d6f61d-db07-451c-9ab3-b9609b6b6f0b").Extract() @@ -104,7 +104,7 @@ func TestCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, SubnetCreateResult) + fmt.Fprint(w, SubnetCreateResult) }) var gatewayIP = "192.168.199.1" @@ -166,7 +166,7 @@ func TestCreateNoGateway(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, SubnetCreateWithNoGatewayResponse) + fmt.Fprint(w, SubnetCreateWithNoGatewayResponse) }) var noGateway = "" @@ -217,7 +217,7 @@ func TestCreateDefaultGateway(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, SubnetCreateWithDefaultGatewayResponse) + fmt.Fprint(w, SubnetCreateWithDefaultGatewayResponse) }) opts := subnets.CreateOpts{ @@ -266,7 +266,7 @@ func TestCreateIPv6RaAddressMode(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, SubnetCreateWithIPv6RaAddressModeResponse) + fmt.Fprint(w, SubnetCreateWithIPv6RaAddressModeResponse) }) var gatewayIP = "2001:db8:0:a::1" @@ -307,7 +307,7 @@ func TestCreateWithNoCIDR(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, SubnetCreateResult) + fmt.Fprint(w, SubnetCreateResult) }) opts := subnets.CreateOpts{ @@ -356,7 +356,7 @@ func TestCreateWithPrefixlen(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, SubnetCreateResult) + fmt.Fprint(w, SubnetCreateResult) }) opts := subnets.CreateOpts{ @@ -423,7 +423,7 @@ func TestUpdate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, SubnetUpdateResponse) + fmt.Fprint(w, SubnetUpdateResponse) }) dnsNameservers := []string{"foo"} @@ -456,7 +456,7 @@ func TestUpdateGateway(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, SubnetUpdateGatewayResponse) + fmt.Fprint(w, SubnetUpdateGatewayResponse) }) var gatewayIP = "10.0.0.1" @@ -487,7 +487,7 @@ func TestUpdateRemoveGateway(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, SubnetUpdateRemoveGatewayResponse) + fmt.Fprint(w, SubnetUpdateRemoveGatewayResponse) }) var noGateway = "" @@ -518,7 +518,7 @@ func TestUpdateHostRoutes(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, SubnetUpdateHostRoutesResponse) + fmt.Fprint(w, SubnetUpdateHostRoutesResponse) }) HostRoutes := []subnets.HostRoute{ @@ -555,7 +555,7 @@ func TestUpdateRemoveHostRoutes(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, SubnetUpdateRemoveHostRoutesResponse) + fmt.Fprint(w, SubnetUpdateRemoveHostRoutesResponse) }) noHostRoutes := []subnets.HostRoute{} @@ -584,7 +584,7 @@ func TestUpdateAllocationPool(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, SubnetUpdateAllocationPoolResponse) + fmt.Fprint(w, SubnetUpdateAllocationPoolResponse) }) name := "my_new_subnet" @@ -625,7 +625,7 @@ func TestUpdateRevision(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, SubnetUpdateResponse) + fmt.Fprint(w, SubnetUpdateResponse) }) th.Mux.HandleFunc("/v2.0/subnets/08eae331-0402-425a-923c-34f7cfe39c1c", func(w http.ResponseWriter, r *http.Request) { @@ -639,7 +639,7 @@ func TestUpdateRevision(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, SubnetUpdateResponse) + fmt.Fprint(w, SubnetUpdateResponse) }) dnsNameservers := []string{"foo"} diff --git a/openstack/objectstorage/v1/containers/testing/fixtures.go b/openstack/objectstorage/v1/containers/testing/fixtures.go index 0f440472ac..55f4f723b6 100644 --- a/openstack/objectstorage/v1/containers/testing/fixtures.go +++ b/openstack/objectstorage/v1/containers/testing/fixtures.go @@ -56,7 +56,7 @@ func HandleListContainerInfoSuccessfully(t *testing.T) { marker := r.Form.Get("marker") switch marker { case "": - fmt.Fprintf(w, `[ + fmt.Fprint(w, `[ { "count": 0, "bytes": 0, @@ -69,7 +69,7 @@ func HandleListContainerInfoSuccessfully(t *testing.T) { } ]`) case "janeausten": - fmt.Fprintf(w, `[ + fmt.Fprint(w, `[ { "count": 1, "bytes": 14, @@ -77,7 +77,7 @@ func HandleListContainerInfoSuccessfully(t *testing.T) { } ]`) case "marktwain": - fmt.Fprintf(w, `[]`) + fmt.Fprint(w, `[]`) default: t.Fatalf("Unexpected marker: [%s]", marker) } @@ -158,7 +158,7 @@ func HandleBulkDeleteSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, bulkDeleteResponse) + fmt.Fprint(w, bulkDeleteResponse) }) } diff --git a/openstack/objectstorage/v1/objects/testing/fixtures_test.go b/openstack/objectstorage/v1/objects/testing/fixtures_test.go index fd24937f6c..f4546d6ab0 100644 --- a/openstack/objectstorage/v1/objects/testing/fixtures_test.go +++ b/openstack/objectstorage/v1/objects/testing/fixtures_test.go @@ -61,7 +61,7 @@ func HandleDownloadObjectSuccessfully(t *testing.T, options ...option) { } w.Header().Set("Last-Modified", date.Format(time.RFC1123)) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, "Successful download with Gophercloud") + fmt.Fprint(w, "Successful download with Gophercloud") }) } @@ -118,7 +118,7 @@ func HandleListObjectsInfoSuccessfully(t *testing.T, options ...option) { marker := r.Form.Get("marker") switch marker { case "": - fmt.Fprintf(w, `[ + fmt.Fprint(w, `[ { "hash": "451e372e48e0f6b1114fa0724aa79fa1", "last_modified": "2016-08-17T22:11:58.602650", @@ -135,7 +135,7 @@ func HandleListObjectsInfoSuccessfully(t *testing.T, options ...option) { } ]`) case "hello": - fmt.Fprintf(w, `[]`) + fmt.Fprint(w, `[]`) default: t.Fatalf("Unexpected marker: [%s]", marker) } @@ -157,13 +157,13 @@ func HandleListSubdirSuccessfully(t *testing.T) { marker := r.Form.Get("marker") switch marker { case "": - fmt.Fprintf(w, `[ + fmt.Fprint(w, `[ { "subdir": "directory/" } ]`) case "directory/": - fmt.Fprintf(w, `[]`) + fmt.Fprint(w, `[]`) default: t.Fatalf("Unexpected marker: [%s]", marker) } @@ -323,7 +323,7 @@ func HandleBulkDeleteSuccessfully(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, bulkDeleteResponse) + fmt.Fprint(w, bulkDeleteResponse) }) } diff --git a/openstack/objectstorage/v1/swauth/testing/fixtures_test.go b/openstack/objectstorage/v1/swauth/testing/fixtures_test.go index b8e0b33f24..01bbfd1a84 100644 --- a/openstack/objectstorage/v1/swauth/testing/fixtures_test.go +++ b/openstack/objectstorage/v1/swauth/testing/fixtures_test.go @@ -24,6 +24,6 @@ func HandleAuthSuccessfully(t *testing.T, authOpts swauth.AuthOpts) { w.Header().Add("X-Auth-Token", AuthResult.Token) w.Header().Add("X-Storage-Url", AuthResult.StorageURL) - fmt.Fprintf(w, "") + fmt.Fprint(w, "") }) } diff --git a/openstack/orchestration/v1/apiversions/testing/requests_test.go b/openstack/orchestration/v1/apiversions/testing/requests_test.go index ec4ad6d228..d7149f1cbd 100644 --- a/openstack/orchestration/v1/apiversions/testing/requests_test.go +++ b/openstack/orchestration/v1/apiversions/testing/requests_test.go @@ -24,7 +24,7 @@ func TestListVersions(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "versions": [ { diff --git a/openstack/orchestration/v1/buildinfo/testing/fixtures_test.go b/openstack/orchestration/v1/buildinfo/testing/fixtures_test.go index 72527032d8..74a91e4df3 100644 --- a/openstack/orchestration/v1/buildinfo/testing/fixtures_test.go +++ b/openstack/orchestration/v1/buildinfo/testing/fixtures_test.go @@ -41,6 +41,6 @@ func HandleGetSuccessfully(t *testing.T, output string) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, output) + fmt.Fprint(w, output) }) } diff --git a/openstack/orchestration/v1/stackevents/testing/fixtures_test.go b/openstack/orchestration/v1/stackevents/testing/fixtures_test.go index 4c22428a9a..a0e31b4ba5 100644 --- a/openstack/orchestration/v1/stackevents/testing/fixtures_test.go +++ b/openstack/orchestration/v1/stackevents/testing/fixtures_test.go @@ -128,7 +128,7 @@ func HandleFindSuccessfully(t *testing.T, output string) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, output) + fmt.Fprint(w, output) }) } @@ -250,9 +250,9 @@ func HandleListSuccessfully(t *testing.T, output string) { marker := r.Form.Get("marker") switch marker { case "": - fmt.Fprintf(w, output) + fmt.Fprint(w, output) case "93940999-7d40-44ae-8de4-19624e7b8d18": - fmt.Fprintf(w, `{"events":[]}`) + fmt.Fprint(w, `{"events":[]}`) default: t.Fatalf("Unexpected marker: [%s]", marker) } @@ -377,9 +377,9 @@ func HandleListResourceEventsSuccessfully(t *testing.T, output string) { marker := r.Form.Get("marker") switch marker { case "": - fmt.Fprintf(w, output) + fmt.Fprint(w, output) case "93940999-7d40-44ae-8de4-19624e7b8d18": - fmt.Fprintf(w, `{"events":[]}`) + fmt.Fprint(w, `{"events":[]}`) default: t.Fatalf("Unexpected marker: [%s]", marker) } @@ -449,6 +449,6 @@ func HandleGetSuccessfully(t *testing.T, output string) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, output) + fmt.Fprint(w, output) }) } diff --git a/openstack/orchestration/v1/stackresources/testing/fixtures_test.go b/openstack/orchestration/v1/stackresources/testing/fixtures_test.go index a306d8de8b..fa1e66575e 100644 --- a/openstack/orchestration/v1/stackresources/testing/fixtures_test.go +++ b/openstack/orchestration/v1/stackresources/testing/fixtures_test.go @@ -82,7 +82,7 @@ func HandleFindSuccessfully(t *testing.T, output string) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, output) + fmt.Fprint(w, output) }) } @@ -157,9 +157,9 @@ func HandleListSuccessfully(t *testing.T, output string) { marker := r.Form.Get("marker") switch marker { case "": - fmt.Fprintf(w, output) + fmt.Fprint(w, output) case "49181cd6-169a-4130-9455-31185bbfc5bf": - fmt.Fprintf(w, `{"resources":[]}`) + fmt.Fprint(w, `{"resources":[]}`) default: t.Fatalf("Unexpected marker: [%s]", marker) } @@ -227,7 +227,7 @@ func HandleGetSuccessfully(t *testing.T, output string) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, output) + fmt.Fprint(w, output) }) } @@ -256,7 +256,7 @@ func HandleMetadataSuccessfully(t *testing.T, output string) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, output) + fmt.Fprint(w, output) }) } @@ -309,7 +309,7 @@ func HandleListTypesSuccessfully(t *testing.T, output string) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, output) + fmt.Fprint(w, output) }) } @@ -370,7 +370,7 @@ func HandleGetSchemaSuccessfully(t *testing.T, output string) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, output) + fmt.Fprint(w, output) }) } @@ -440,7 +440,7 @@ func HandleGetTemplateSuccessfully(t *testing.T, output string) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, output) + fmt.Fprint(w, output) }) } diff --git a/openstack/orchestration/v1/stacks/testing/fixtures_test.go b/openstack/orchestration/v1/stacks/testing/fixtures_test.go index 2244b7d89d..9baed3aced 100644 --- a/openstack/orchestration/v1/stacks/testing/fixtures_test.go +++ b/openstack/orchestration/v1/stacks/testing/fixtures_test.go @@ -48,7 +48,7 @@ func HandleCreateSuccessfully(t *testing.T, output string) { th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) th.TestHeader(t, r, "Accept", "application/json") w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, output) + fmt.Fprint(w, output) }) } @@ -142,9 +142,9 @@ func HandleListSuccessfully(t *testing.T, output string) { marker := r.Form.Get("marker") switch marker { case "": - fmt.Fprintf(w, output) + fmt.Fprint(w, output) case "db6977b2-27aa-4775-9ae7-6213212d4ada": - fmt.Fprintf(w, `[]`) + fmt.Fprint(w, `[]`) default: t.Fatalf("Unexpected marker: [%s]", marker) } @@ -221,7 +221,7 @@ func HandleGetSuccessfully(t *testing.T, output string) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, output) + fmt.Fprint(w, output) }) } @@ -233,7 +233,7 @@ func HandleFindSuccessfully(t *testing.T, output string) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, output) + fmt.Fprint(w, output) }) } @@ -309,7 +309,7 @@ func HandlePreviewSuccessfully(t *testing.T, output string) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, output) + fmt.Fprint(w, output) }) } @@ -432,6 +432,6 @@ func HandleAbandonSuccessfully(t *testing.T, output string) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, output) + fmt.Fprint(w, output) }) } diff --git a/openstack/orchestration/v1/stacks/utils_test.go b/openstack/orchestration/v1/stacks/utils_test.go index 07fbb90cba..b7dd86bf0e 100644 --- a/openstack/orchestration/v1/stacks/utils_test.go +++ b/openstack/orchestration/v1/stacks/utils_test.go @@ -68,7 +68,7 @@ func TestFetch(t *testing.T) { th.TestMethod(t, r, "GET") w.Header().Set("Content-Type", "application/jason") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, "Fee-fi-fo-fum") + fmt.Fprint(w, "Fee-fi-fo-fum") }) client := fakeClient{BaseClient: getHTTPClient()} diff --git a/openstack/orchestration/v1/stacktemplates/testing/fixtures_test.go b/openstack/orchestration/v1/stacktemplates/testing/fixtures_test.go index 5b9c9ad345..2e6505702e 100644 --- a/openstack/orchestration/v1/stacktemplates/testing/fixtures_test.go +++ b/openstack/orchestration/v1/stacktemplates/testing/fixtures_test.go @@ -48,7 +48,7 @@ func HandleGetSuccessfully(t *testing.T, output string) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, output) + fmt.Fprint(w, output) }) } @@ -91,6 +91,6 @@ func HandleValidateSuccessfully(t *testing.T, output string) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, output) + fmt.Fprint(w, output) }) } diff --git a/openstack/placement/v1/resourceproviders/testing/fixtures_test.go b/openstack/placement/v1/resourceproviders/testing/fixtures_test.go index e663cab280..8766d88e27 100644 --- a/openstack/placement/v1/resourceproviders/testing/fixtures_test.go +++ b/openstack/placement/v1/resourceproviders/testing/fixtures_test.go @@ -277,7 +277,7 @@ func HandleResourceProviderList(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ResourceProvidersBody) + fmt.Fprint(w, ResourceProvidersBody) }) } @@ -289,7 +289,7 @@ func HandleResourceProviderCreate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ResourceProviderCreateBody) + fmt.Fprint(w, ResourceProviderCreateBody) }) } @@ -301,7 +301,7 @@ func HandleResourceProviderGet(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ResourceProviderCreateBody) + fmt.Fprint(w, ResourceProviderCreateBody) }) } @@ -324,7 +324,7 @@ func HandleResourceProviderUpdate(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ResourceProviderUpdateResponse) + fmt.Fprint(w, ResourceProviderUpdateResponse) }) } @@ -339,7 +339,7 @@ func HandleResourceProviderGetUsages(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, UsagesBody) + fmt.Fprint(w, UsagesBody) }) } @@ -354,7 +354,7 @@ func HandleResourceProviderGetInventories(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, InventoriesBody) + fmt.Fprint(w, InventoriesBody) }) } @@ -369,7 +369,7 @@ func HandleResourceProviderGetAllocations(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, AllocationsBody) + fmt.Fprint(w, AllocationsBody) }) } @@ -384,6 +384,6 @@ func HandleResourceProviderGetTraits(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, TraitsBody) + fmt.Fprint(w, TraitsBody) }) } diff --git a/openstack/sharedfilesystems/apiversions/testing/fixtures_test.go b/openstack/sharedfilesystems/apiversions/testing/fixtures_test.go index 949434480f..37826cab70 100644 --- a/openstack/sharedfilesystems/apiversions/testing/fixtures_test.go +++ b/openstack/sharedfilesystems/apiversions/testing/fixtures_test.go @@ -186,7 +186,7 @@ func MockListResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ManilaAllAPIVersionsResponse) + fmt.Fprint(w, ManilaAllAPIVersionsResponse) }) } @@ -198,7 +198,7 @@ func MockGetResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ManilaAPIVersionResponse) + fmt.Fprint(w, ManilaAPIVersionResponse) }) } @@ -210,7 +210,7 @@ func MockGetNoResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ManilaAPIInvalidVersionResponse_1) + fmt.Fprint(w, ManilaAPIInvalidVersionResponse_1) }) } @@ -222,6 +222,6 @@ func MockGetMultipleResponses(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ManilaAPIInvalidVersionResponse_2) + fmt.Fprint(w, ManilaAPIInvalidVersionResponse_2) }) } diff --git a/openstack/sharedfilesystems/v2/availabilityzones/testing/fixtures_test.go b/openstack/sharedfilesystems/v2/availabilityzones/testing/fixtures_test.go index d6cd25830f..fa18c4cfc9 100644 --- a/openstack/sharedfilesystems/v2/availabilityzones/testing/fixtures_test.go +++ b/openstack/sharedfilesystems/v2/availabilityzones/testing/fixtures_test.go @@ -17,7 +17,7 @@ func MockListResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "availability_zones": [ { diff --git a/openstack/sharedfilesystems/v2/errors/testing/fixtures_test.go b/openstack/sharedfilesystems/v2/errors/testing/fixtures_test.go index 5a6f7f013c..3adbc89b25 100644 --- a/openstack/sharedfilesystems/v2/errors/testing/fixtures_test.go +++ b/openstack/sharedfilesystems/v2/errors/testing/fixtures_test.go @@ -37,6 +37,6 @@ func MockCreateResponse(t *testing.T) { th.TestJSONRequest(t, r, createRequest) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusNotFound) - fmt.Fprintf(w, createResponse) + fmt.Fprint(w, createResponse) }) } diff --git a/openstack/sharedfilesystems/v2/messages/testing/fixtures_test.go b/openstack/sharedfilesystems/v2/messages/testing/fixtures_test.go index 111b6dbf97..123bad35ce 100644 --- a/openstack/sharedfilesystems/v2/messages/testing/fixtures_test.go +++ b/openstack/sharedfilesystems/v2/messages/testing/fixtures_test.go @@ -25,7 +25,7 @@ func MockListResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "messages": [ { @@ -67,7 +67,7 @@ func MockFilteredListResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "messages": [ { @@ -95,7 +95,7 @@ func MockGetResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "message": { "resource_id": "4336d74f-3bdc-4f27-9657-c01ec63680bf", diff --git a/openstack/sharedfilesystems/v2/replicas/testing/fixtures_test.go b/openstack/sharedfilesystems/v2/replicas/testing/fixtures_test.go index 00585c9c26..41fa0164c9 100644 --- a/openstack/sharedfilesystems/v2/replicas/testing/fixtures_test.go +++ b/openstack/sharedfilesystems/v2/replicas/testing/fixtures_test.go @@ -48,7 +48,7 @@ func MockCreateResponse(t *testing.T) { th.TestJSONRequest(t, r, createRequest) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, createResponse) + fmt.Fprint(w, createResponse) }) } @@ -175,7 +175,7 @@ func MockGetResponse(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) th.TestHeader(t, r, "X-OpenStack-Manila-API-Version", "2.11") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, getResponse) + fmt.Fprint(w, getResponse) }) } @@ -330,7 +330,7 @@ func MockListExportLocationsResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") th.TestHeader(t, r, "X-OpenStack-Manila-API-Version", "2.47") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, listExportLocationsResponse) + fmt.Fprint(w, listExportLocationsResponse) }) } @@ -355,6 +355,6 @@ func MockGetExportLocationResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") th.TestHeader(t, r, "X-OpenStack-Manila-API-Version", "2.47") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, getExportLocationResponse) + fmt.Fprint(w, getExportLocationResponse) }) } diff --git a/openstack/sharedfilesystems/v2/schedulerstats/testing/fixtures_test.go b/openstack/sharedfilesystems/v2/schedulerstats/testing/fixtures_test.go index 88c4b31203..fdd861d9c8 100644 --- a/openstack/sharedfilesystems/v2/schedulerstats/testing/fixtures_test.go +++ b/openstack/sharedfilesystems/v2/schedulerstats/testing/fixtures_test.go @@ -274,7 +274,7 @@ func HandlePoolsListSuccessfully(t *testing.T) { if err := r.ParseForm(); err != nil { t.Errorf("Failed to parse request form %v", err) } - fmt.Fprintf(w, PoolsListBody) + fmt.Fprint(w, PoolsListBody) }) th.Mux.HandleFunc("/scheduler-stats/pools/detail", func(w http.ResponseWriter, r *http.Request) { @@ -286,6 +286,6 @@ func HandlePoolsListSuccessfully(t *testing.T) { if err := r.ParseForm(); err != nil { t.Errorf("Failed to parse request form %v", err) } - fmt.Fprintf(w, PoolsListBodyDetail) + fmt.Fprint(w, PoolsListBodyDetail) }) } diff --git a/openstack/sharedfilesystems/v2/securityservices/testing/fixtures_test.go b/openstack/sharedfilesystems/v2/securityservices/testing/fixtures_test.go index c0b7645770..279fcee4a4 100644 --- a/openstack/sharedfilesystems/v2/securityservices/testing/fixtures_test.go +++ b/openstack/sharedfilesystems/v2/securityservices/testing/fixtures_test.go @@ -30,7 +30,7 @@ func MockCreateResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "security_service": { "status": "new", @@ -67,7 +67,7 @@ func MockListResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "security_services": [ { @@ -113,7 +113,7 @@ func MockFilteredListResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "security_services": [ { @@ -143,7 +143,7 @@ func MockGetResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "security_service": { "status": "new", @@ -169,7 +169,7 @@ func MockUpdateResponse(t *testing.T) { th.TestMethod(t, r, "PUT") th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "security_service": { "status": "new", diff --git a/openstack/sharedfilesystems/v2/services/testing/fixtures_test.go b/openstack/sharedfilesystems/v2/services/testing/fixtures_test.go index 67f7b94c78..9916b033fc 100644 --- a/openstack/sharedfilesystems/v2/services/testing/fixtures_test.go +++ b/openstack/sharedfilesystems/v2/services/testing/fixtures_test.go @@ -66,6 +66,6 @@ func HandleListSuccessfully(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, ServiceListBody) + fmt.Fprint(w, ServiceListBody) }) } diff --git a/openstack/sharedfilesystems/v2/shareaccessrules/testing/fixtures_test.go b/openstack/sharedfilesystems/v2/shareaccessrules/testing/fixtures_test.go index d82014357d..cc63ffac9c 100644 --- a/openstack/sharedfilesystems/v2/shareaccessrules/testing/fixtures_test.go +++ b/openstack/sharedfilesystems/v2/shareaccessrules/testing/fixtures_test.go @@ -40,7 +40,7 @@ func MockGetResponse(t *testing.T) { th.TestHeader(t, r, "Accept", "application/json") w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, getResponse) + fmt.Fprint(w, getResponse) }) } diff --git a/openstack/sharedfilesystems/v2/shareaccessrules/testing/requests_test.go b/openstack/sharedfilesystems/v2/shareaccessrules/testing/requests_test.go index 4f86a642d4..7566788e40 100644 --- a/openstack/sharedfilesystems/v2/shareaccessrules/testing/requests_test.go +++ b/openstack/sharedfilesystems/v2/shareaccessrules/testing/requests_test.go @@ -49,6 +49,6 @@ func MockListResponse(t *testing.T) { th.TestHeader(t, r, "Accept", "application/json") w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, listResponse) + fmt.Fprint(w, listResponse) }) } diff --git a/openstack/sharedfilesystems/v2/sharenetworks/testing/fixtures_test.go b/openstack/sharedfilesystems/v2/sharenetworks/testing/fixtures_test.go index cfa3b1712d..eb608f9b6a 100644 --- a/openstack/sharedfilesystems/v2/sharenetworks/testing/fixtures_test.go +++ b/openstack/sharedfilesystems/v2/sharenetworks/testing/fixtures_test.go @@ -55,7 +55,7 @@ func MockCreateResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, createResp("my_network", + fmt.Fprint(w, createResp("my_network", "This is my share network", "998b42ee-2cee-4d36-8b95-67b5ca1f2109", "53482b62-2c84-4a53-b6ab-30d9d9800d06")) @@ -85,7 +85,7 @@ func MockListResponse(t *testing.T) { switch marker { case "": - fmt.Fprintf(w, `{ + fmt.Fprint(w, `{ "share_networks": [ { "name": "net_my1", @@ -135,7 +135,7 @@ func MockListResponse(t *testing.T) { ] }`) default: - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "share_networks": [] }`) @@ -157,7 +157,7 @@ func MockFilteredListResponse(t *testing.T) { marker := r.Form.Get("offset") switch marker { case "": - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "share_networks": [ { @@ -178,7 +178,7 @@ func MockFilteredListResponse(t *testing.T) { ] }`) case "1": - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "share_networks": [ { @@ -199,7 +199,7 @@ func MockFilteredListResponse(t *testing.T) { ] }`) case "2": - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "share_networks": [ { @@ -220,7 +220,7 @@ func MockFilteredListResponse(t *testing.T) { ] }`) default: - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "share_networks": [] }`) @@ -235,7 +235,7 @@ func MockGetResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "share_network": { "name": "net_my1", @@ -261,7 +261,7 @@ func MockUpdateNeutronResponse(t *testing.T) { th.TestMethod(t, r, "PUT") th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "share_network": { "name": "net_my2", @@ -288,7 +288,7 @@ func MockUpdateNovaResponse(t *testing.T) { th.TestMethod(t, r, "PUT") th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "share_network": { "name": "net_my2", @@ -315,7 +315,7 @@ func MockAddSecurityServiceResponse(t *testing.T) { th.TestMethod(t, r, "POST") th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "share_network": { "name": "net2", @@ -341,7 +341,7 @@ func MockRemoveSecurityServiceResponse(t *testing.T) { th.TestMethod(t, r, "POST") th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "share_network": { "name": "net2", diff --git a/openstack/sharedfilesystems/v2/shares/testing/fixtures_test.go b/openstack/sharedfilesystems/v2/shares/testing/fixtures_test.go index cfb9e73d2e..36db8b7a22 100644 --- a/openstack/sharedfilesystems/v2/shares/testing/fixtures_test.go +++ b/openstack/sharedfilesystems/v2/shares/testing/fixtures_test.go @@ -84,7 +84,7 @@ func MockCreateResponse(t *testing.T) { th.TestJSONRequest(t, r, createRequest) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, createResponse) + fmt.Fprint(w, createResponse) }) } @@ -158,7 +158,7 @@ func MockUpdateResponse(t *testing.T) { th.TestJSONRequest(t, r, updateRequest) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, updateResponse) + fmt.Fprint(w, updateResponse) }) } @@ -211,7 +211,7 @@ func MockGetResponse(t *testing.T) { th.TestMethod(t, r, "GET") th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, getResponse) + fmt.Fprint(w, getResponse) }) } @@ -304,7 +304,7 @@ func MockListExportLocationsResponse(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, listExportLocationsResponse) + fmt.Fprint(w, listExportLocationsResponse) }) } @@ -325,7 +325,7 @@ func MockGetExportLocationResponse(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, getExportLocationResponse) + fmt.Fprint(w, getExportLocationResponse) }) } @@ -359,7 +359,7 @@ func MockGrantAccessResponse(t *testing.T) { th.TestJSONRequest(t, r, grantAccessRequest) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, grantAccessResponse) + fmt.Fprint(w, grantAccessResponse) }) } @@ -410,7 +410,7 @@ func MockListAccessRightsResponse(t *testing.T) { th.TestJSONRequest(t, r, listAccessRightsRequest) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, listAccessRightsResponse) + fmt.Fprint(w, listAccessRightsResponse) }) } diff --git a/openstack/sharedfilesystems/v2/sharetransfers/testing/fixtures_test.go b/openstack/sharedfilesystems/v2/sharetransfers/testing/fixtures_test.go index 980292f38f..342c4c5101 100644 --- a/openstack/sharedfilesystems/v2/sharetransfers/testing/fixtures_test.go +++ b/openstack/sharedfilesystems/v2/sharetransfers/testing/fixtures_test.go @@ -147,7 +147,7 @@ func HandleCreateTransfer(t *testing.T) { th.TestJSONRequest(t, r, CreateRequest) w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, CreateResponse) + fmt.Fprint(w, CreateResponse) }) } @@ -179,7 +179,7 @@ func HandleListTransfers(t *testing.T) { th.TestFormValues(t, r, map[string]string{"all_tenants": "true"}) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListOutput) + fmt.Fprint(w, ListOutput) }) } @@ -191,7 +191,7 @@ func HandleListTransfersDetail(t *testing.T) { th.TestFormValues(t, r, map[string]string{"all_tenants": "true"}) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ListOutput) + fmt.Fprint(w, ListOutput) }) } @@ -202,6 +202,6 @@ func HandleGetTransfer(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, GetOutput) + fmt.Fprint(w, GetOutput) }) } diff --git a/openstack/sharedfilesystems/v2/sharetypes/testing/fixtures_test.go b/openstack/sharedfilesystems/v2/sharetypes/testing/fixtures_test.go index 767d42807a..17fb21fa78 100644 --- a/openstack/sharedfilesystems/v2/sharetypes/testing/fixtures_test.go +++ b/openstack/sharedfilesystems/v2/sharetypes/testing/fixtures_test.go @@ -30,7 +30,7 @@ func MockCreateResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "volume_type": { "os-share-type-access:is_public": true, @@ -76,7 +76,7 @@ func MockListResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "volume_types": [ { @@ -141,7 +141,7 @@ func MockGetDefaultResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "volume_type": { "required_extra_specs": null, @@ -172,7 +172,7 @@ func MockGetExtraSpecsResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "extra_specs": { "snapshot_support": "True", @@ -199,7 +199,7 @@ func MockSetExtraSpecsResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "extra_specs": { "my_key": "my_value" @@ -223,7 +223,7 @@ func MockShowAccessResponse(t *testing.T) { w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "share_type_access": [ { diff --git a/openstack/sharedfilesystems/v2/snapshots/testing/fixtures_test.go b/openstack/sharedfilesystems/v2/snapshots/testing/fixtures_test.go index e34d1081a4..88e94c371a 100644 --- a/openstack/sharedfilesystems/v2/snapshots/testing/fixtures_test.go +++ b/openstack/sharedfilesystems/v2/snapshots/testing/fixtures_test.go @@ -59,7 +59,7 @@ func MockCreateResponse(t *testing.T) { th.TestJSONRequest(t, r, createRequest) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusAccepted) - fmt.Fprintf(w, createResponse) + fmt.Fprint(w, createResponse) }) } @@ -114,7 +114,7 @@ func MockUpdateResponse(t *testing.T) { th.TestJSONRequest(t, r, updateRequest) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, updateResponse) + fmt.Fprint(w, updateResponse) }) } @@ -150,7 +150,7 @@ func MockGetResponse(t *testing.T) { th.TestMethod(t, r, "GET") th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, getResponse) + fmt.Fprint(w, getResponse) }) } diff --git a/openstack/testing/client_test.go b/openstack/testing/client_test.go index 2c158dbfc3..75192a524c 100644 --- a/openstack/testing/client_test.go +++ b/openstack/testing/client_test.go @@ -46,7 +46,7 @@ func TestAuthenticatedClientV3(t *testing.T) { w.Header().Add("X-Subject-Token", ID) w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, `{ "token": { "expires_at": "2013-02-02T18:30:59.000000Z" } }`) + fmt.Fprint(w, `{ "token": { "expires_at": "2013-02-02T18:30:59.000000Z" } }`) }) options := gophercloud.AuthOptions{ @@ -91,7 +91,7 @@ func TestAuthenticatedClientV2(t *testing.T) { }) th.Mux.HandleFunc("/v2.0/tokens", func(w http.ResponseWriter, r *http.Request) { - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "access": { "token": { @@ -197,7 +197,7 @@ func TestIdentityAdminV3Client(t *testing.T) { w.Header().Add("X-Subject-Token", ID) w.WriteHeader(http.StatusCreated) - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "token": { "audit_ids": ["VcxU2JYqT8OzfUVvrjEITQ", "qNUTIJntTzO1-XUk5STybw"], diff --git a/openstack/workflow/v2/crontriggers/testing/requests_test.go b/openstack/workflow/v2/crontriggers/testing/requests_test.go index fd3bac58e0..8267e2bc79 100644 --- a/openstack/workflow/v2/crontriggers/testing/requests_test.go +++ b/openstack/workflow/v2/crontriggers/testing/requests_test.go @@ -25,7 +25,7 @@ func TestCreateCronTrigger(t *testing.T) { w.WriteHeader(http.StatusCreated) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "created_at": "2018-09-12 15:48:18", "first_execution_time": "2018-09-12 17:48:00", @@ -110,7 +110,7 @@ func TestGetCronTrigger(t *testing.T) { th.TestMethod(t, r, "GET") th.TestHeader(t, r, "X-Auth-token", fake.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "created_at": "2018-09-12 15:48:18", "first_execution_time": "2018-09-12 17:48:00", @@ -195,7 +195,7 @@ func TestListCronTriggers(t *testing.T) { "next": "%s/cron_triggers?marker=0520ffd8-f7f1-4f2e-845b-55d953a1cf46" }`, th.Server.URL) case "0520ffd8-f7f1-4f2e-845b-55d953a1cf46": - fmt.Fprintf(w, `{ "cron_triggers": [] }`) + fmt.Fprint(w, `{ "cron_triggers": [] }`) default: t.Fatalf("Unexpected marker: [%s]", marker) } diff --git a/openstack/workflow/v2/executions/testing/requests_test.go b/openstack/workflow/v2/executions/testing/requests_test.go index d0b4641793..86a4700457 100644 --- a/openstack/workflow/v2/executions/testing/requests_test.go +++ b/openstack/workflow/v2/executions/testing/requests_test.go @@ -25,7 +25,7 @@ func TestCreateExecution(t *testing.T) { w.WriteHeader(http.StatusCreated) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "created_at": "2018-09-12 14:48:49", "description": "description", @@ -92,7 +92,7 @@ func TestGetExecution(t *testing.T) { th.TestHeader(t, r, "X-Auth-token", fake.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "created_at": "2018-09-12 14:48:49", "description": "description", @@ -189,7 +189,7 @@ func TestListExecutions(t *testing.T) { "next": "%s/executions?marker=50bb59f1-eb77-4017-a77f-6d575b002667" }`, th.Server.URL) case "50bb59f1-eb77-4017-a77f-6d575b002667": - fmt.Fprintf(w, `{ "executions": [] }`) + fmt.Fprint(w, `{ "executions": [] }`) default: t.Fatalf("Unexpected marker: [%s]", marker) } diff --git a/openstack/workflow/v2/workflows/testing/requests_test.go b/openstack/workflow/v2/workflows/testing/requests_test.go index 78f0f78a09..a5d656685f 100644 --- a/openstack/workflow/v2/workflows/testing/requests_test.go +++ b/openstack/workflow/v2/workflows/testing/requests_test.go @@ -46,11 +46,11 @@ workflow_echo: w.WriteHeader(http.StatusCreated) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, `{ + fmt.Fprint(w, `{ "workflows": [ { "created_at": "2018-09-12 15:48:17", - "definition": "---\nversion: '2.0'\n\nworkflow_echo:\n description: Simple workflow example\n type: direct\n\n input:\n - msg\n\n tasks:\n test:\n action: std.echo output=\"<%% $.msg %%>\"", + "definition": "---\nversion: '2.0'\n\nworkflow_echo:\n description: Simple workflow example\n type: direct\n\n input:\n - msg\n\n tasks:\n test:\n action: std.echo output=\"<% $.msg %>\"", "id": "604a3a1e-94e3-4066-a34a-aa56873ef236", "input": "msg", "name": "workflow_echo", @@ -118,10 +118,10 @@ func TestGetWorkflow(t *testing.T) { th.TestMethod(t, r, "GET") th.TestHeader(t, r, "X-Auth-token", fake.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, ` + fmt.Fprint(w, ` { "created_at": "2018-09-12 15:48:17", - "definition": "---\nversion: '2.0'\n\nworkflow_echo:\n description: Simple workflow example\n type: direct\n\n input:\n - msg\n\n tasks:\n test:\n action: std.echo output=\"<%% $.msg %%>\"", + "definition": "---\nversion: '2.0'\n\nworkflow_echo:\n description: Simple workflow example\n type: direct\n\n input:\n - msg\n\n tasks:\n test:\n action: std.echo output=\"<% $.msg %>\"", "id": "604a3a1e-94e3-4066-a34a-aa56873ef236", "input": "msg", "name": "workflow_echo", @@ -187,7 +187,7 @@ func TestListWorkflows(t *testing.T) { ] }`, th.Server.URL) case "604a3a1e-94e3-4066-a34a-aa56873ef236": - fmt.Fprintf(w, `{ "workflows": [] }`) + fmt.Fprint(w, `{ "workflows": [] }`) default: t.Fatalf("Unexpected marker: [%s]", marker) } diff --git a/pagination/testing/linked_test.go b/pagination/testing/linked_test.go index 25166ad861..e28c2b0483 100644 --- a/pagination/testing/linked_test.go +++ b/pagination/testing/linked_test.go @@ -45,7 +45,7 @@ func createLinked() pagination.Pager { th.Mux.HandleFunc("/page3", func(w http.ResponseWriter, r *http.Request) { w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, `{ "ints": [7, 8, 9], "links": { "next": null } }`) + fmt.Fprint(w, `{ "ints": [7, 8, 9], "links": { "next": null } }`) }) client := createClient() diff --git a/pagination/testing/marker_test.go b/pagination/testing/marker_test.go index 45c943e5b7..a41915175d 100644 --- a/pagination/testing/marker_test.go +++ b/pagination/testing/marker_test.go @@ -46,11 +46,11 @@ func createMarkerPaged(t *testing.T) pagination.Pager { ms := r.Form["marker"] switch { case len(ms) == 0: - fmt.Fprintf(w, "aaa\nbbb\nccc") + fmt.Fprint(w, "aaa\nbbb\nccc") case len(ms) == 1 && ms[0] == "ccc": - fmt.Fprintf(w, "ddd\neee\nfff") + fmt.Fprint(w, "ddd\neee\nfff") case len(ms) == 1 && ms[0] == "fff": - fmt.Fprintf(w, "ggg\nhhh\niii") + fmt.Fprint(w, "ggg\nhhh\niii") case len(ms) == 1 && ms[0] == "iii": w.WriteHeader(http.StatusNoContent) default: diff --git a/pagination/testing/single_test.go b/pagination/testing/single_test.go index 6bcd930cb2..090324a573 100644 --- a/pagination/testing/single_test.go +++ b/pagination/testing/single_test.go @@ -38,7 +38,7 @@ func setupSinglePaged() pagination.Pager { th.Mux.HandleFunc("/only", func(w http.ResponseWriter, r *http.Request) { w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, `{ "ints": [1, 2, 3] }`) + fmt.Fprint(w, `{ "ints": [1, 2, 3] }`) }) createPage := func(r pagination.PageResult) pagination.Page { diff --git a/testhelper/fixture/helper.go b/testhelper/fixture/helper.go index a0f3b5c7b2..7c84378770 100644 --- a/testhelper/fixture/helper.go +++ b/testhelper/fixture/helper.go @@ -25,7 +25,7 @@ func SetupHandler(t *testing.T, url, method, requestBody, responseBody string, s w.WriteHeader(status) if responseBody != "" { - fmt.Fprintf(w, responseBody) + fmt.Fprint(w, responseBody) } }) } diff --git a/testing/provider_client_test.go b/testing/provider_client_test.go index 18704fd4b1..44fc37756c 100644 --- a/testing/provider_client_test.go +++ b/testing/provider_client_test.go @@ -99,7 +99,7 @@ func TestConcurrentReauth(t *testing.T) { } w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, `{}`) + fmt.Fprint(w, `{}`) }) wg := new(sync.WaitGroup) @@ -276,7 +276,7 @@ func TestRequestThatCameDuringReauthWaitsUntilItIsCompleted(t *testing.T) { } w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, `{}`) + fmt.Fprint(w, `{}`) }) wg := new(sync.WaitGroup) From 0d4b68d9c7a4fe5e0461bff8d423efd6819fa7fe Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 28 Nov 2024 14:11:35 +0000 Subject: [PATCH 074/429] make: Bump golangci-lint We also add the '-v' and '--max-same-issues' flags so that we get some indication that things are running and show more output. Signed-off-by: Stephen Finucane --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 066946cf8d..2a0618a6b6 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ undefine GOFLAGS -GOLANGCI_LINT_VERSION?=v1.57.1 -GO_TEST?=go run gotest.tools/gotestsum@latest --format testname +GOLANGCI_LINT_VERSION?=v1.62.2 +GO_TEST?=go run gotest.tools/gotestsum@latest --format testname -- ifeq ($(shell command -v podman 2> /dev/null),) RUNNER=docker @@ -23,7 +23,7 @@ lint: -v ~/.cache/golangci-lint/$(GOLANGCI_LINT_VERSION):/root/.cache \ -w /app \ -e GOFLAGS="-tags=acceptance" \ - golangci/golangci-lint:$(GOLANGCI_LINT_VERSION) golangci-lint run + golangci/golangci-lint:$(GOLANGCI_LINT_VERSION) golangci-lint run -v --max-same-issues 50 .PHONY: lint format: From bdfd59d2de6e136237b66a95561813d0c94b37c0 Mon Sep 17 00:00:00 2001 From: Derek Higgins Date: Wed, 13 Nov 2024 10:28:17 +0000 Subject: [PATCH 075/429] Add support for disable_power_off Added in baremetal api v1.95 disable_power_off expcicitly prevents a node from being powered off by ironic. See https://specs.openstack.org/openstack/ironic-specs/specs/approved/nc-si.html --- openstack/baremetal/v1/nodes/requests.go | 4 ++++ openstack/baremetal/v1/nodes/results.go | 4 ++++ openstack/baremetal/v1/nodes/testing/fixtures_test.go | 5 +++++ 3 files changed, 13 insertions(+) diff --git a/openstack/baremetal/v1/nodes/requests.go b/openstack/baremetal/v1/nodes/requests.go index 8cb0de9e05..8b2eb4b218 100644 --- a/openstack/baremetal/v1/nodes/requests.go +++ b/openstack/baremetal/v1/nodes/requests.go @@ -274,6 +274,10 @@ type CreateOpts struct { // Static network configuration to use during deployment and cleaning. NetworkData map[string]any `json:"network_data,omitempty"` + + // Whether disable_power_off is enabled or disabled on this node. + // Requires microversion 1.95 or later. + DisablePowerOff *bool `json:"disable_power_off,omitempty"` } // ToNodeCreateMap assembles a request body based on the contents of a CreateOpts. diff --git a/openstack/baremetal/v1/nodes/results.go b/openstack/baremetal/v1/nodes/results.go index 22babe02d3..507e0d6a4f 100644 --- a/openstack/baremetal/v1/nodes/results.go +++ b/openstack/baremetal/v1/nodes/results.go @@ -314,6 +314,10 @@ type Node struct { // The UTC date and time when the resource was updated, ISO 8601 format. May be “null”. UpdatedAt time.Time `json:"updated_at"` + + // Whether disable_power_off is enabled or disabled on this node. + // Requires microversion 1.95 or later. + DisablePowerOff bool `json:"disable_power_off"` } // NodePage abstracts the raw results of making a List() request against diff --git a/openstack/baremetal/v1/nodes/testing/fixtures_test.go b/openstack/baremetal/v1/nodes/testing/fixtures_test.go index 10589c5f1b..88abebcebb 100644 --- a/openstack/baremetal/v1/nodes/testing/fixtures_test.go +++ b/openstack/baremetal/v1/nodes/testing/fixtures_test.go @@ -87,6 +87,7 @@ const NodeListDetailBody = ` "created_at": "2019-01-31T19:59:28+00:00", "deploy_interface": "iscsi", "deploy_step": {}, + "disable_power_off": false, "driver": "ipmi", "driver_info": { "ipmi_port": "6230", @@ -195,6 +196,7 @@ const NodeListDetailBody = ` "created_at": "2019-01-31T19:59:29+00:00", "deploy_interface": "iscsi", "deploy_step": {}, + "disable_power_off": false, "driver": "ipmi", "driver_info": {}, "driver_internal_info": {}, @@ -295,6 +297,7 @@ const NodeListDetailBody = ` "created_at": "2019-01-31T19:59:30+00:00", "deploy_interface": "iscsi", "deploy_step": {}, + "disable_power_off": true, "driver": "ipmi", "driver_info": {}, "driver_internal_info": {}, @@ -1123,6 +1126,7 @@ var ( InspectionFinishedAt: &InspectionFinishedAt, Retired: false, RetiredReason: "No longer needed", + DisablePowerOff: false, Links: []nodes.Link{ {Href: "http://ironic.example.com:6385/v1/nodes/08c84581-58f5-4ea2-a0c6-dd2e5d2b3662", Rel: "self"}, {Href: "http://ironic.example.com:6385/nodes/08c84581-58f5-4ea2-a0c6-dd2e5d2b3662", Rel: "bookmark"}, @@ -1192,6 +1196,7 @@ var ( UpdatedAt: updatedAt, Retired: false, RetiredReason: "No longer needed", + DisablePowerOff: true, Links: []nodes.Link{ {Href: "http://ironic.example.com:6385/v1/nodes/c9afd385-5d89-4ecb-9e1c-68194da6b474", Rel: "self"}, {Href: "http://ironic.example.com:6385/nodes/c9afd385-5d89-4ecb-9e1c-68194da6b474", Rel: "bookmark"}, From c5e3f8e32a54a33d2516cce3ff50e6fe7ad5c01c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Dec 2024 10:00:56 +0000 Subject: [PATCH 076/429] build(deps): bump golang.org/x/crypto from 0.29.0 to 0.30.0 Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.29.0 to 0.30.0. - [Commits](https://github.com/golang/crypto/compare/v0.29.0...v0.30.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 45961985de..dc5d92e323 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module github.com/gophercloud/gophercloud/v2 go 1.22 require ( - golang.org/x/crypto v0.29.0 + golang.org/x/crypto v0.30.0 gopkg.in/yaml.v2 v2.4.0 ) -require golang.org/x/sys v0.27.0 // indirect +require golang.org/x/sys v0.28.0 // indirect diff --git a/go.sum b/go.sum index a14f597436..1812f7828d 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ -golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= -golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= -golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= -golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= -golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= +golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY= +golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= From 88ca397dfe8d28f868cf6a703d91215df04a8dee Mon Sep 17 00:00:00 2001 From: Pierre Prinetti Date: Fri, 6 Dec 2024 16:03:36 +0100 Subject: [PATCH 077/429] labels: Add edit:testinfra The `edit:testinfra` label was added to `labeler.yaml` for automatic labeling based on path, but not to the list of managed labels. With this change `edit:testinfra` is added to the list of managed labels, so that automation doesn't fight to create and remove it. --- .github/labels.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/labels.yaml b/.github/labels.yaml index ad21863831..f0f9eefd80 100644 --- a/.github/labels.yaml +++ b/.github/labels.yaml @@ -105,6 +105,9 @@ - color: '000000' description: This PR updates sharedfilesystems code name: edit:sharedfilesystems +- color: '000000' + description: This PR updates testing infrastructure code + name: edit:testinfra - color: '000000' description: This PR updates testing code name: edit:testing From d5ca800b92dc7a65bb8d9a24bcf4755f9afbdaca Mon Sep 17 00:00:00 2001 From: chuliang Date: Mon, 4 Sep 2023 13:56:18 +0000 Subject: [PATCH 078/429] identity: Add Get endpoint by ID Co-Authored-By: chuliang Co-Authored-By: Pierre Prinetti Co-Authored-By: Stephen Finucane --- .../openstack/identity/v3/endpoint_test.go | 23 +++ openstack/identity/v3/endpoints/requests.go | 7 + openstack/identity/v3/endpoints/results.go | 6 + .../v3/endpoints/testing/requests_test.go | 169 +++++++++++------- openstack/identity/v3/projects/doc.go | 2 +- 5 files changed, 137 insertions(+), 70 deletions(-) diff --git a/internal/acceptance/openstack/identity/v3/endpoint_test.go b/internal/acceptance/openstack/identity/v3/endpoint_test.go index ae2254102a..8dd9e5bad1 100644 --- a/internal/acceptance/openstack/identity/v3/endpoint_test.go +++ b/internal/acceptance/openstack/identity/v3/endpoint_test.go @@ -39,6 +39,29 @@ func TestEndpointsList(t *testing.T) { th.AssertEquals(t, found, true) } +func TestEndpointsGet(t *testing.T) { + clients.RequireAdmin(t) + + client, err := clients.NewIdentityV3Client() + th.AssertNoErr(t, err) + + allPages, err := endpoints.List(client, nil).AllPages(context.TODO()) + th.AssertNoErr(t, err) + + allEndpoints, err := endpoints.ExtractEndpoints(allPages) + th.AssertNoErr(t, err) + + endpoint := allEndpoints[0] + e, err := endpoints.Get(context.TODO(), client, endpoint.ID).Extract() + if err != nil { + t.Fatalf("Unable to get endpoint: %v", err) + } + + tools.PrintResource(t, e) + + th.AssertEquals(t, e.Name, e.Name) +} + func TestEndpointsNavigateCatalog(t *testing.T) { clients.RequireAdmin(t) diff --git a/openstack/identity/v3/endpoints/requests.go b/openstack/identity/v3/endpoints/requests.go index 35eb966077..4386bb9bc9 100644 --- a/openstack/identity/v3/endpoints/requests.go +++ b/openstack/identity/v3/endpoints/requests.go @@ -90,6 +90,13 @@ func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pa }) } +// Get retrieves details on a single endpoint, by ID. +func Get(ctx context.Context, client *gophercloud.ServiceClient, id string) (r GetResult) { + resp, err := client.Get(ctx, endpointURL(client, id), &r.Body, nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + // UpdateOptsBuilder allows extensions to add parameters to the Update request. type UpdateOptsBuilder interface { ToEndpointUpdateMap() (map[string]any, error) diff --git a/openstack/identity/v3/endpoints/results.go b/openstack/identity/v3/endpoints/results.go index 9efec30af2..19d279ebc6 100644 --- a/openstack/identity/v3/endpoints/results.go +++ b/openstack/identity/v3/endpoints/results.go @@ -19,6 +19,12 @@ func (r commonResult) Extract() (*Endpoint, error) { return s.Endpoint, err } +// GetResult is the response from a Get operation. Call its Extract method +// to interpret it as an Endpoint. +type GetResult struct { + commonResult +} + // CreateResult is the response from a Create operation. Call its Extract // method to interpret it as an Endpoint. type CreateResult struct { diff --git a/openstack/identity/v3/endpoints/testing/requests_test.go b/openstack/identity/v3/endpoints/testing/requests_test.go index 348a1f1c6e..ad138acd49 100644 --- a/openstack/identity/v3/endpoints/testing/requests_test.go +++ b/openstack/identity/v3/endpoints/testing/requests_test.go @@ -20,35 +20,31 @@ func TestCreateSuccessful(t *testing.T) { th.Mux.HandleFunc("/endpoints", func(w http.ResponseWriter, r *http.Request) { th.TestMethod(t, r, "POST") th.TestHeader(t, r, "X-Auth-Token", client.TokenID) - th.TestJSONRequest(t, r, ` - { - "endpoint": { - "interface": "public", - "name": "the-endiest-of-points", - "region": "underground", - "url": "https://1.2.3.4:9000/", - "service_id": "asdfasdfasdfasdf" - } - } - `) + th.TestJSONRequest(t, r, `{ + "endpoint": { + "interface": "public", + "name": "the-endiest-of-points", + "region": "underground", + "url": "https://1.2.3.4:9000/", + "service_id": "asdfasdfasdfasdf" + } + }`) w.WriteHeader(http.StatusCreated) - fmt.Fprint(w, ` - { - "endpoint": { - "id": "12", - "interface": "public", - "enabled": true, - "links": { - "self": "https://localhost:5000/v3/endpoints/12" - }, - "name": "the-endiest-of-points", - "region": "underground", - "service_id": "asdfasdfasdfasdf", - "url": "https://1.2.3.4:9000/" - } - } - `) + fmt.Fprint(w, `{ + "endpoint": { + "id": "12", + "interface": "public", + "enabled": true, + "links": { + "self": "https://localhost:5000/v3/endpoints/12" + }, + "name": "the-endiest-of-points", + "region": "underground", + "service_id": "asdfasdfasdfasdf", + "url": "https://1.2.3.4:9000/" + } + }`) }) actual, err := endpoints.Create(context.TODO(), client.ServiceClient(), endpoints.CreateOpts{ @@ -82,40 +78,38 @@ func TestListEndpoints(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprint(w, ` - { - "endpoints": [ - { - "id": "12", - "interface": "public", - "enabled": true, - "links": { - "self": "https://localhost:5000/v3/endpoints/12" - }, - "name": "the-endiest-of-points", - "region": "underground", - "service_id": "asdfasdfasdfasdf", - "url": "https://1.2.3.4:9000/" + fmt.Fprint(w, `{ + "endpoints": [ + { + "id": "12", + "interface": "public", + "enabled": true, + "links": { + "self": "https://localhost:5000/v3/endpoints/12" }, - { - "id": "13", - "interface": "internal", - "enabled": false, - "links": { - "self": "https://localhost:5000/v3/endpoints/13" - }, - "name": "shhhh", - "region": "underground", - "service_id": "asdfasdfasdfasdf", - "url": "https://1.2.3.4:9001/" - } - ], - "links": { - "next": null, - "previous": null + "name": "the-endiest-of-points", + "region": "underground", + "service_id": "asdfasdfasdfasdf", + "url": "https://1.2.3.4:9000/" + }, + { + "id": "13", + "interface": "internal", + "enabled": false, + "links": { + "self": "https://localhost:5000/v3/endpoints/13" + }, + "name": "shhhh", + "region": "underground", + "service_id": "asdfasdfasdfasdf", + "url": "https://1.2.3.4:9001/" } + ], + "links": { + "next": null, + "previous": null } - `) + }`) }) count := 0 @@ -154,6 +148,47 @@ func TestListEndpoints(t *testing.T) { th.AssertEquals(t, 1, count) } +func TestGetEndpoint(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + + th.Mux.HandleFunc("/endpoints/12", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + fmt.Fprint(w, `{ + "endpoint": { + "id": "12", + "interface": "public", + "enabled": true, + "links": { + "self": "https://localhost:5000/v3/endpoints/12" + }, + "name": "the-endiest-of-points", + "region": "underground", + "service_id": "asdfasdfasdfasdf", + "url": "https://1.2.3.4:9000/" + } + }`) + }) + + actual, err := endpoints.Get(context.TODO(), client.ServiceClient(), "12").Extract() + if err != nil { + t.Fatalf("Unexpected error from Get: %v", err) + } + + expected := &endpoints.Endpoint{ + ID: "12", + Availability: gophercloud.AvailabilityPublic, + Enabled: true, + Name: "the-endiest-of-points", + Region: "underground", + ServiceID: "asdfasdfasdfasdf", + URL: "https://1.2.3.4:9000/", + } + th.AssertDeepEquals(t, expected, actual) +} + func TestUpdateEndpoint(t *testing.T) { th.SetupHTTP() defer th.TeardownHTTP() @@ -161,17 +196,14 @@ func TestUpdateEndpoint(t *testing.T) { th.Mux.HandleFunc("/endpoints/12", func(w http.ResponseWriter, r *http.Request) { th.TestMethod(t, r, "PATCH") th.TestHeader(t, r, "X-Auth-Token", client.TokenID) - th.TestJSONRequest(t, r, ` - { - "endpoint": { - "name": "renamed", + th.TestJSONRequest(t, r, `{ + "endpoint": { + "name": "renamed", "region": "somewhere-else" - } - } - `) + } + }`) - fmt.Fprint(w, ` - { + fmt.Fprint(w, `{ "endpoint": { "id": "12", "interface": "public", @@ -184,8 +216,7 @@ func TestUpdateEndpoint(t *testing.T) { "service_id": "asdfasdfasdfasdf", "url": "https://1.2.3.4:9000/" } - } - `) + }`) }) actual, err := endpoints.Update(context.TODO(), client.ServiceClient(), "12", endpoints.UpdateOpts{ diff --git a/openstack/identity/v3/projects/doc.go b/openstack/identity/v3/projects/doc.go index 6aea466a51..6100327397 100644 --- a/openstack/identity/v3/projects/doc.go +++ b/openstack/identity/v3/projects/doc.go @@ -73,7 +73,7 @@ Example to List all tags of a Project panic(err) } -Example to modify all tags of a Project +Example to modify all tags of a Project projectID := "966b3c7d36a24facaf20b7e458bf2192" tags := ["foo", "bar"] From 97c0a325b35aa66b26724d72afb22d03d7296111 Mon Sep 17 00:00:00 2001 From: Stefan Majewsky Date: Mon, 21 Oct 2024 15:46:48 +0200 Subject: [PATCH 079/429] [nova] fix pagination of hypervisors.List() This is a mildly backwards-incompatible change, but since most people only use this API on the level of pagination.Pager, it ought not be a big deal in practice. Closes #3222. --- openstack/compute/v2/hypervisors/requests.go | 2 +- openstack/compute/v2/hypervisors/results.go | 15 +++++++- .../v2/hypervisors/testing/fixtures_test.go | 35 ++++++++++++++++--- .../v2/hypervisors/testing/requests_test.go | 9 +++-- 4 files changed, 49 insertions(+), 12 deletions(-) diff --git a/openstack/compute/v2/hypervisors/requests.go b/openstack/compute/v2/hypervisors/requests.go index 37ecbee17a..b17dd35781 100644 --- a/openstack/compute/v2/hypervisors/requests.go +++ b/openstack/compute/v2/hypervisors/requests.go @@ -53,7 +53,7 @@ func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pa } return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page { - return HypervisorPage{pagination.SinglePageBase(r)} + return HypervisorPage{pagination.LinkedPageBase{PageResult: r}} }) } diff --git a/openstack/compute/v2/hypervisors/results.go b/openstack/compute/v2/hypervisors/results.go index ee6046c6c0..0a35dfdf0f 100644 --- a/openstack/compute/v2/hypervisors/results.go +++ b/openstack/compute/v2/hypervisors/results.go @@ -240,7 +240,7 @@ func (r *Hypervisor) UnmarshalJSON(b []byte) error { // HypervisorPage represents a single page of all Hypervisors from a List // request. type HypervisorPage struct { - pagination.SinglePageBase + pagination.LinkedPageBase } // IsEmpty determines whether or not a HypervisorPage is empty. @@ -253,6 +253,19 @@ func (page HypervisorPage) IsEmpty() (bool, error) { return len(va) == 0, err } +// NextPageURL uses the response's embedded link reference to navigate to the +// next page of results. +func (page HypervisorPage) NextPageURL() (string, error) { + var s struct { + Links []gophercloud.Link `json:"hypervisors_links"` + } + err := page.ExtractInto(&s) + if err != nil { + return "", err + } + return gophercloud.ExtractNextURL(s.Links) +} + // ExtractHypervisors interprets a page of results as a slice of Hypervisors. func ExtractHypervisors(p pagination.Page) ([]Hypervisor, error) { var h struct { diff --git a/openstack/compute/v2/hypervisors/testing/fixtures_test.go b/openstack/compute/v2/hypervisors/testing/fixtures_test.go index fa0b93a3f8..4bdb2c0613 100644 --- a/openstack/compute/v2/hypervisors/testing/fixtures_test.go +++ b/openstack/compute/v2/hypervisors/testing/fixtures_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/gophercloud/gophercloud/v2/openstack/compute/v2/hypervisors" + "github.com/gophercloud/gophercloud/v2/testhelper" th "github.com/gophercloud/gophercloud/v2/testhelper" "github.com/gophercloud/gophercloud/v2/testhelper/client" ) @@ -85,8 +86,8 @@ const HypervisorListBodyPre253 = ` ] }` -// HypervisorListBody represents a raw hypervisor list result with Pike+ release. -const HypervisorListBody = ` +// HypervisorListBodyPage1 represents page 1 of a raw hypervisor list result with Pike+ release. +const HypervisorListBodyPage1 = ` { "hypervisors": [ { @@ -127,7 +128,20 @@ const HypervisorListBody = ` }, "vcpus": 1, "vcpus_used": 0 - }, + } + ], + "hypervisors_links": [ + { + "href": "%s/os-hypervisors/detail?marker=c48f6247-abe4-4a24-824e-ea39e108874f", + "rel": "next" + } + ] +}` + +// HypervisorListBodyPage2 represents page 2 of a raw hypervisor list result with Pike+ release. +const HypervisorListBodyPage2 = ` +{ + "hypervisors": [ { "cpu_info": "{\"arch\": \"x86_64\", \"model\": \"Nehalem\", \"vendor\": \"Intel\", \"features\": [\"pge\", \"clflush\"], \"topology\": {\"cores\": 1, \"threads\": 1, \"sockets\": 4}}", "current_workload": 0, @@ -157,6 +171,9 @@ const HypervisorListBody = ` ] }` +// HypervisorListBodyEmpty represents an empty raw hypervisor list result, marking the end of pagination. +const HypervisorListBodyEmpty = `{ "hypervisors": [] }` + // HypervisorListWithParametersBody represents a raw hypervisor list result with Pike+ release. const HypervisorListWithParametersBody = ` { @@ -624,8 +641,16 @@ func HandleHypervisorListSuccessfully(t *testing.T) { th.TestMethod(t, r, "GET") th.TestHeader(t, r, "X-Auth-Token", client.TokenID) - w.Header().Add("Content-Type", "application/json") - fmt.Fprint(w, HypervisorListBody) + switch r.URL.Query().Get("marker") { + case "": + w.Header().Add("Content-Type", "application/json") + fmt.Fprintf(w, HypervisorListBodyPage1, testhelper.Server.URL) + case "c48f6247-abe4-4a24-824e-ea39e108874f": + w.Header().Add("Content-Type", "application/json") + fmt.Fprint(w, HypervisorListBodyPage2) + default: + http.Error(w, "unexpected marker value", http.StatusInternalServerError) + } }) } diff --git a/openstack/compute/v2/hypervisors/testing/requests_test.go b/openstack/compute/v2/hypervisors/testing/requests_test.go index 0303f7f1d0..5acf7d0d1a 100644 --- a/openstack/compute/v2/hypervisors/testing/requests_test.go +++ b/openstack/compute/v2/hypervisors/testing/requests_test.go @@ -69,19 +69,18 @@ func TestListHypervisors(t *testing.T) { return false, err } - if len(actual) != 2 { - t.Fatalf("Expected 2 hypervisors, got %d", len(actual)) + if len(actual) != 1 { + t.Fatalf("Expected 1 hypervisors on page %d, got %d", pages, len(actual)) } th.CheckDeepEquals(t, HypervisorFake, actual[0]) - th.CheckDeepEquals(t, HypervisorFake, actual[1]) return true, nil }) th.AssertNoErr(t, err) - if pages != 1 { - t.Errorf("Expected 1 page, saw %d", pages) + if pages != 2 { + t.Errorf("Expected 2 pages, saw %d", pages) } } From 19a73fb7933cbc53f9de5304ce63b44c45a7c9a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Fri, 6 Dec 2024 18:08:53 +0100 Subject: [PATCH 080/429] trivial: change order of args for AssertEquals() calls The expected order is "expected, actual" and getting this right helps debugging. --- .../networking/v2/extensions/extensions.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/internal/acceptance/openstack/networking/v2/extensions/extensions.go b/internal/acceptance/openstack/networking/v2/extensions/extensions.go index 4de1401f4d..84f020ff38 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/extensions.go +++ b/internal/acceptance/openstack/networking/v2/extensions/extensions.go @@ -43,8 +43,8 @@ func CreateExternalNetwork(t *testing.T, client *gophercloud.ServiceClient) (*ne t.Logf("Created external network: %s", networkName) - th.AssertEquals(t, network.Name, networkName) - th.AssertEquals(t, network.Description, networkDescription) + th.AssertEquals(t, networkName, network.Name) + th.AssertEquals(t, networkDescription, network.Description) return network, nil } @@ -74,9 +74,9 @@ func CreatePortWithSecurityGroup(t *testing.T, client *gophercloud.ServiceClient t.Logf("Successfully created port: %s", portName) - th.AssertEquals(t, port.Name, portName) - th.AssertEquals(t, port.Description, portDescription) - th.AssertEquals(t, port.NetworkID, networkID) + th.AssertEquals(t, portName, port.Name) + th.AssertEquals(t, portDescription, port.Description) + th.AssertEquals(t, networkID, port.NetworkID) return port, nil } @@ -101,8 +101,8 @@ func CreateSecurityGroup(t *testing.T, client *gophercloud.ServiceClient) (*grou t.Logf("Created security group: %s", secGroup.ID) - th.AssertEquals(t, secGroup.Name, secGroupName) - th.AssertEquals(t, secGroup.Description, secGroupDescription) + th.AssertEquals(t, secGroupName, secGroup.Name) + th.AssertEquals(t, secGroupDescription, secGroup.Description) return secGroup, nil } From c925eeacebf44c92577e9310c05bd3b6245cf012 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Sun, 8 Dec 2024 22:34:47 +0100 Subject: [PATCH 081/429] Allow BuildRequestBody() to work with collection of structs When passing an array or a slice to `BuildRequestBody()`, the `parent` string becomes mandatory. This makes it possible to build requests for bulk operations. --- params.go | 52 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/params.go b/params.go index 09b322a6a2..4a2ed6c942 100644 --- a/params.go +++ b/params.go @@ -11,9 +11,11 @@ import ( ) /* -BuildRequestBody builds a map[string]interface from the given `struct`. If -parent is not an empty string, the final map[string]interface returned will -encapsulate the built one. For example: +BuildRequestBody builds a map[string]interface from the given `struct`, or +collection of `structs`. If parent is not an empty string, the final +map[string]interface returned will encapsulate the built one. Parent is +required when passing a list of `structs`. +For example: disk := 1 createOpts := flavors.CreateOpts{ @@ -27,7 +29,29 @@ encapsulate the built one. For example: body, err := gophercloud.BuildRequestBody(createOpts, "flavor") -The above example can be run as-is, however it is recommended to look at how + + opts := []rules.CreateOpts{ + { + Direction: "ingress", + PortRangeMin: 80, + EtherType: rules.EtherType4, + PortRangeMax: 80, + Protocol: "tcp", + SecGroupID: "a7734e61-b545-452d-a3cd-0189cbd9747a", + }, + { + Direction: "ingress", + PortRangeMin: 443, + EtherType: rules.EtherType4, + PortRangeMax: 443, + Protocol: "tcp", + SecGroupID: "a7734e61-b545-452d-a3cd-0189cbd9747a", + }, + } + + body, err := gophercloud.BuildRequestBody(opts, "security_group_rules") + +The above examples can be run as-is, however it is recommended to look at how BuildRequestBody is used within Gophercloud to more fully understand how it fits within the request process as a whole rather than use it directly as shown above. @@ -44,7 +68,8 @@ func BuildRequestBody(opts any, parent string) (map[string]any, error) { } optsMap := make(map[string]any) - if optsValue.Kind() == reflect.Struct { + switch optsValue.Kind() { + case reflect.Struct: //fmt.Printf("optsValue.Kind() is a reflect.Struct: %+v\n", optsValue.Kind()) for i := 0; i < optsValue.NumField(); i++ { v := optsValue.Field(i) @@ -184,9 +209,22 @@ func BuildRequestBody(opts any, parent string) (map[string]any, error) { } //fmt.Printf("optsMap after parent added: %+v\n", optsMap) return optsMap, nil + case reflect.Slice, reflect.Array: + optsMaps := make([]map[string]any, optsValue.Len()) + for i := 0; i < optsValue.Len(); i++ { + b, err := BuildRequestBody(optsValue.Index(i).Interface(), "") + if err != nil { + return nil, err + } + optsMaps[i] = b + } + if parent == "" { + return nil, fmt.Errorf("Parent is required when passing an array or a slice.") + } + return map[string]any{parent: optsMaps}, nil } - // Return an error if the underlying type of 'opts' isn't a struct. - return nil, fmt.Errorf("Options type is not a struct.") + // Return an error if we can't work with the underlying type of 'opts' + return nil, fmt.Errorf("Options type is not a struct, a slice, or an array.") } // EnabledState is a convenience type, mostly used in Create and Update From 6e6dbe5bbcaaa4428852966b70b6405197ec9d59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Fri, 6 Dec 2024 17:53:37 +0100 Subject: [PATCH 082/429] SG rules: implement bulk create Implement bulk creation of security group rules [1]. [1] https://docs.openstack.org/api-ref/network/v2/#bulk-create-security-group-rule --- .../networking/v2/extensions/extensions.go | 38 ++++++++ .../networking/v2/extensions/security_test.go | 6 ++ .../v2/extensions/security/rules/requests.go | 17 ++++ .../v2/extensions/security/rules/results.go | 19 ++++ .../security/rules/testing/requests_test.go | 95 +++++++++++++++++++ 5 files changed, 175 insertions(+) diff --git a/internal/acceptance/openstack/networking/v2/extensions/extensions.go b/internal/acceptance/openstack/networking/v2/extensions/extensions.go index 4de1401f4d..4eb9df5cf2 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/extensions.go +++ b/internal/acceptance/openstack/networking/v2/extensions/extensions.go @@ -140,6 +140,44 @@ func CreateSecurityGroupRule(t *testing.T, client *gophercloud.ServiceClient, se return rule, nil } +// CreateSecurityGroupRulesBulk will create security group rules with a random name +// and random port between 80 and 99. +// An error will be returned if one was failed to be created. +func CreateSecurityGroupRulesBulk(t *testing.T, client *gophercloud.ServiceClient, secGroupID string) ([]rules.SecGroupRule, error) { + t.Logf("Attempting to bulk create security group rules in group: %s", secGroupID) + + sgRulesCreateOpts := make([]rules.CreateOpts, 3) + for i := range 3 { + description := "Rule description" + fromPort := tools.RandomInt(80, 89) + toPort := tools.RandomInt(90, 99) + + sgRulesCreateOpts[i] = rules.CreateOpts{ + Description: description, + Direction: "ingress", + EtherType: "IPv4", + SecGroupID: secGroupID, + PortRangeMin: fromPort, + PortRangeMax: toPort, + Protocol: rules.ProtocolTCP, + } + } + + rules, err := rules.CreateBulk(context.TODO(), client, sgRulesCreateOpts).Extract() + if err != nil { + return rules, err + } + + for i, rule := range rules { + t.Logf("Created security group rule: %s", rule.ID) + + th.AssertEquals(t, sgRulesCreateOpts[i].SecGroupID, rule.SecGroupID) + th.AssertEquals(t, sgRulesCreateOpts[i].Description, rule.Description) + } + + return rules, nil +} + // DeleteSecurityGroup will delete a security group of a specified ID. // A fatal error will occur if the deletion failed. This works best as a // deferred function diff --git a/internal/acceptance/openstack/networking/v2/extensions/security_test.go b/internal/acceptance/openstack/networking/v2/extensions/security_test.go index 670735ec5e..8d855bbb0a 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/security_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/security_test.go @@ -26,6 +26,12 @@ func TestSecurityGroupsCreateUpdateDelete(t *testing.T) { th.AssertNoErr(t, err) defer DeleteSecurityGroupRule(t, client, rule.ID) + rules, err := CreateSecurityGroupRulesBulk(t, client, group.ID) + th.AssertNoErr(t, err) + for _, r := range rules { + defer DeleteSecurityGroupRule(t, client, r.ID) + } + tools.PrintResource(t, group) var name = "Update group" diff --git a/openstack/networking/v2/extensions/security/rules/requests.go b/openstack/networking/v2/extensions/security/rules/requests.go index f2ea9f2d16..8976224b42 100644 --- a/openstack/networking/v2/extensions/security/rules/requests.go +++ b/openstack/networking/v2/extensions/security/rules/requests.go @@ -150,6 +150,23 @@ func Create(ctx context.Context, c *gophercloud.ServiceClient, opts CreateOptsBu return } +// CreateBulk is an operation which adds new security group rules and associates them +// with an existing security group (whose ID is specified in CreateOpts). +// As of Dalmatian (2024.2) neutron only allows bulk creation of rules when +// they all belong to the same tenant and security group. +// https://github.com/openstack/neutron/blob/6183792/neutron/db/securitygroups_db.py#L814-L828 +func CreateBulk(ctx context.Context, c *gophercloud.ServiceClient, opts []CreateOpts) (r CreateBulkResult) { + body, err := gophercloud.BuildRequestBody(opts, "security_group_rules") + if err != nil { + r.Err = err + return + } + + resp, err := c.Post(ctx, rootURL(c), body, &r.Body, nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + // Get retrieves a particular security group rule based on its unique ID. func Get(ctx context.Context, c *gophercloud.ServiceClient, id string) (r GetResult) { resp, err := c.Get(ctx, resourceURL(c, id), &r.Body, nil) diff --git a/openstack/networking/v2/extensions/security/rules/results.go b/openstack/networking/v2/extensions/security/rules/results.go index cfdb27fa17..0901ced578 100644 --- a/openstack/networking/v2/extensions/security/rules/results.go +++ b/openstack/networking/v2/extensions/security/rules/results.go @@ -103,6 +103,10 @@ type commonResult struct { gophercloud.Result } +type bulkResult struct { + gophercloud.Result +} + // Extract is a function that accepts a result and extracts a security rule. func (r commonResult) Extract() (*SecGroupRule, error) { var s struct { @@ -112,12 +116,27 @@ func (r commonResult) Extract() (*SecGroupRule, error) { return s.SecGroupRule, err } +// Extract is a function that accepts a result and extracts security rules. +func (r bulkResult) Extract() ([]SecGroupRule, error) { + var s struct { + SecGroupRules []SecGroupRule `json:"security_group_rules"` + } + err := r.ExtractInto(&s) + return s.SecGroupRules, err +} + // CreateResult represents the result of a create operation. Call its Extract // method to interpret it as a SecGroupRule. type CreateResult struct { commonResult } +// CreateBulkResult represents the result of a bulk create operation. Call its +// Extract method to interpret it as a slice of SecGroupRules. +type CreateBulkResult struct { + bulkResult +} + // GetResult represents the result of a get operation. Call its Extract // method to interpret it as a SecGroupRule. type GetResult struct { diff --git a/openstack/networking/v2/extensions/security/rules/testing/requests_test.go b/openstack/networking/v2/extensions/security/rules/testing/requests_test.go index 843d7eb202..10aa461908 100644 --- a/openstack/networking/v2/extensions/security/rules/testing/requests_test.go +++ b/openstack/networking/v2/extensions/security/rules/testing/requests_test.go @@ -222,6 +222,101 @@ func TestCreateAnyProtocol(t *testing.T) { th.AssertNoErr(t, err) } +func TestCreateBulk(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + + th.Mux.HandleFunc("/v2.0/security-group-rules", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestJSONRequest(t, r, ` +{ + "security_group_rules": [ + { + "description": "test description of rule", + "direction": "ingress", + "port_range_min": 80, + "ethertype": "IPv4", + "port_range_max": 80, + "protocol": "tcp", + "remote_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "security_group_id": "a7734e61-b545-452d-a3cd-0189cbd9747a" + }, + { + "description": "test description of rule", + "direction": "ingress", + "port_range_min": 443, + "ethertype": "IPv4", + "port_range_max": 443, + "protocol": "tcp", + "security_group_id": "a7734e61-b545-452d-a3cd-0189cbd9747a" + } + ] +} + `) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + + fmt.Fprint(w, ` +{ + "security_group_rules": [ + { + "description": "test description of rule", + "direction": "ingress", + "ethertype": "IPv4", + "port_range_max": 80, + "port_range_min": 80, + "protocol": "tcp", + "remote_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", + "remote_ip_prefix": null, + "security_group_id": "a7734e61-b545-452d-a3cd-0189cbd9747a", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + }, + { + "description": "test description of rule", + "direction": "ingress", + "ethertype": "IPv4", + "port_range_max": 443, + "port_range_min": 443, + "protocol": "tcp", + "remote_group_id": null, + "remote_ip_prefix": null, + "security_group_id": "a7734e61-b545-452d-a3cd-0189cbd9747a", + "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" + } + ] +} + `) + }) + + opts := []rules.CreateOpts{ + { + Description: "test description of rule", + Direction: "ingress", + PortRangeMin: 80, + EtherType: rules.EtherType4, + PortRangeMax: 80, + Protocol: "tcp", + RemoteGroupID: "85cc3048-abc3-43cc-89b3-377341426ac5", + SecGroupID: "a7734e61-b545-452d-a3cd-0189cbd9747a", + }, + { + Description: "test description of rule", + Direction: "ingress", + PortRangeMin: 443, + EtherType: rules.EtherType4, + PortRangeMax: 443, + Protocol: "tcp", + SecGroupID: "a7734e61-b545-452d-a3cd-0189cbd9747a", + }, + } + _, err := rules.CreateBulk(context.TODO(), fake.ServiceClient(), opts).Extract() + th.AssertNoErr(t, err) +} + func TestRequiredCreateOpts(t *testing.T) { res := rules.Create(context.TODO(), fake.ServiceClient(), rules.CreateOpts{Direction: rules.DirIngress}) if res.Err == nil { From 53d13552640adfc3749772624972946dadf19349 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Dec 2024 14:27:03 +0000 Subject: [PATCH 083/429] build(deps): bump golang.org/x/crypto from 0.30.0 to 0.31.0 Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.30.0 to 0.31.0. - [Commits](https://github.com/golang/crypto/compare/v0.30.0...v0.31.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index dc5d92e323..3c5d9e0e23 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/gophercloud/gophercloud/v2 go 1.22 require ( - golang.org/x/crypto v0.30.0 + golang.org/x/crypto v0.31.0 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index 1812f7828d..428bb87959 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY= -golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= From 026af19b1fe0a2973dd50b58c2e0499763cfedb8 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Wed, 18 Dec 2024 15:49:58 +0000 Subject: [PATCH 084/429] compute: Merge keypair CreateOptsExt This was missed in v2. Correct it in v3. Signed-off-by: Stephen Finucane --- .../openstack/compute/v2/compute.go | 8 +++--- openstack/compute/v2/keypairs/doc.go | 8 ++---- openstack/compute/v2/keypairs/requests.go | 26 ------------------- openstack/compute/v2/servers/requests.go | 3 +++ .../v2/flavors/testing/fixtures.go | 2 +- 5 files changed, 9 insertions(+), 38 deletions(-) diff --git a/internal/acceptance/openstack/compute/v2/compute.go b/internal/acceptance/openstack/compute/v2/compute.go index 4a5ec655a2..3d5da42a6c 100644 --- a/internal/acceptance/openstack/compute/v2/compute.go +++ b/internal/acceptance/openstack/compute/v2/compute.go @@ -685,19 +685,17 @@ func CreateServerWithPublicKey(t *testing.T, client *gophercloud.ServiceClient, name := tools.RandomString("ACPTTEST", 16) t.Logf("Attempting to create server: %s", name) - serverCreateOpts := servers.CreateOpts{ + createOpts := servers.CreateOpts{ Name: name, FlavorRef: choices.FlavorID, ImageRef: choices.ImageID, Networks: []servers.Network{ {UUID: networkID}, }, + KeyName: keyPairName, } - server, err := servers.Create(context.TODO(), client, keypairs.CreateOptsExt{ - CreateOptsBuilder: serverCreateOpts, - KeyName: keyPairName, - }, nil).Extract() + server, err := servers.Create(context.TODO(), client, createOpts, nil).Extract() if err != nil { return nil, err } diff --git a/openstack/compute/v2/keypairs/doc.go b/openstack/compute/v2/keypairs/doc.go index 0e52dfc9a3..b54d7945da 100644 --- a/openstack/compute/v2/keypairs/doc.go +++ b/openstack/compute/v2/keypairs/doc.go @@ -87,15 +87,11 @@ Example to Delete a Key Pair owned by a certain user using microversion 2.10 or Example to Create a Server With a Key Pair - serverCreateOpts := servers.CreateOpts{ + createOpts := servers.CreateOpts{ Name: "server_name", ImageRef: "image-uuid", FlavorRef: "flavor-uuid", - } - - createOpts := keypairs.CreateOptsExt{ - CreateOptsBuilder: serverCreateOpts, - KeyName: "keypair-name", + KeyName: "keypair-name", } server, err := servers.Create(context.TODO(), computeClient, createOpts).Extract() diff --git a/openstack/compute/v2/keypairs/requests.go b/openstack/compute/v2/keypairs/requests.go index bc4cc270f1..b2d17c73b9 100644 --- a/openstack/compute/v2/keypairs/requests.go +++ b/openstack/compute/v2/keypairs/requests.go @@ -4,35 +4,9 @@ import ( "context" "github.com/gophercloud/gophercloud/v2" - "github.com/gophercloud/gophercloud/v2/openstack/compute/v2/servers" "github.com/gophercloud/gophercloud/v2/pagination" ) -// CreateOptsExt adds a KeyPair option to the base CreateOpts. -type CreateOptsExt struct { - servers.CreateOptsBuilder - - // KeyName is the name of the key pair. - KeyName string `json:"key_name,omitempty"` -} - -// ToServerCreateMap adds the key_name to the base server creation options. -func (opts CreateOptsExt) ToServerCreateMap() (map[string]any, error) { - base, err := opts.CreateOptsBuilder.ToServerCreateMap() - if err != nil { - return nil, err - } - - if opts.KeyName == "" { - return base, nil - } - - serverMap := base["server"].(map[string]any) - serverMap["key_name"] = opts.KeyName - - return base, nil -} - // ListOptsBuilder allows extensions to add additional parameters to the // List request. type ListOptsBuilder interface { diff --git a/openstack/compute/v2/servers/requests.go b/openstack/compute/v2/servers/requests.go index d7d5ad81c1..f9c3bf0657 100644 --- a/openstack/compute/v2/servers/requests.go +++ b/openstack/compute/v2/servers/requests.go @@ -508,6 +508,9 @@ type CreateOpts struct { // DiskConfig [optional] controls how the created server's disk is partitioned. DiskConfig DiskConfig `json:"OS-DCF:diskConfig,omitempty"` + + // KeyName is the name of the key pair. + KeyName string `json:"key_name,omitempty"` } // ToServerCreateMap assembles a request body based on the contents of a diff --git a/openstack/loadbalancer/v2/flavors/testing/fixtures.go b/openstack/loadbalancer/v2/flavors/testing/fixtures.go index b5b14e5fa3..b33166dfa2 100644 --- a/openstack/loadbalancer/v2/flavors/testing/fixtures.go +++ b/openstack/loadbalancer/v2/flavors/testing/fixtures.go @@ -165,7 +165,7 @@ func HandleFlavorCreationSuccessfullyDisabled(t *testing.T, response string) { w.WriteHeader(http.StatusAccepted) w.Header().Add("Content-Type", "application/json") - fmt.Fprintf(w, response) + fmt.Fprint(w, response) }) } From 434d932996e23871f5224e254774bceb72a3ca5c Mon Sep 17 00:00:00 2001 From: Pierre Prinetti Date: Fri, 20 Dec 2024 12:13:35 +0100 Subject: [PATCH 085/429] Rename development branch from `master` to `main` --- .github/CONTRIBUTING.md | 6 +++--- .github/ISSUE_TEMPLATE | 2 +- .github/PULL_REQUEST_TEMPLATE | 2 +- .github/workflows/ensure-labels.yaml | 2 +- .github/workflows/greetings.yaml | 4 ++-- README.md | 2 +- docs/contributor-tutorial/step-05-pull-requests.md | 6 +++--- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index af0bdb979a..ed777696ba 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -9,7 +9,7 @@ ## New Contributor Tutorial For new contributors, we've put together a detailed tutorial -[here](https://github.com/gophercloud/gophercloud/tree/master/docs/contributor-tutorial)! +[here](https://github.com/gophercloud/gophercloud/tree/main/docs/contributor-tutorial)! ## 3 ways to get involved @@ -89,7 +89,7 @@ fork as `origin` instead: 4. Checkout the latest development branch: ```bash - git checkout master + git checkout main ``` 5. If you're working on something (discussed more in detail below), you will @@ -107,7 +107,7 @@ need to checkout a new feature branch: git commit ``` -7. Submit your branch as a [Pull Request](https://help.github.com/articles/creating-a-pull-request/). When submitting a Pull Request, please follow our [Style Guide](https://github.com/gophercloud/gophercloud/blob/master/docs/STYLEGUIDE.md). +7. Submit your branch as a [Pull Request](https://help.github.com/articles/creating-a-pull-request/). When submitting a Pull Request, please follow our [Style Guide](https://github.com/gophercloud/gophercloud/blob/main/docs/STYLEGUIDE.md). > Further information about using Git can be found [here](https://git-scm.com/book/en/v2). diff --git a/.github/ISSUE_TEMPLATE b/.github/ISSUE_TEMPLATE index da9c8472d6..d4db3bdab9 100644 --- a/.github/ISSUE_TEMPLATE +++ b/.github/ISSUE_TEMPLATE @@ -1,3 +1,3 @@ diff --git a/.github/PULL_REQUEST_TEMPLATE b/.github/PULL_REQUEST_TEMPLATE index fb271a3334..03aa4bb3dd 100644 --- a/.github/PULL_REQUEST_TEMPLATE +++ b/.github/PULL_REQUEST_TEMPLATE @@ -1,6 +1,6 @@ diff --git a/.github/ISSUE_TEMPLATE/bug.yaml b/.github/ISSUE_TEMPLATE/bug.yaml new file mode 100644 index 0000000000..7aff19fe7d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug.yaml @@ -0,0 +1,29 @@ +name: Bug Report +description: File a bug report. +title: "[Bug]: " +# type: Bug ## Not supported yet, despite docs saying otherwise: https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-issue-forms#top-level-syntax +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! Check out our [contributor guide](https://github.com/gophercloud/gophercloud/blob/main/docs/contributor-tutorial/step-02-issues.md) to create effective issues. + - type: textarea + id: what-happened + attributes: + label: What happened? + description: Also tell us, what did you expect to happen? + placeholder: What happened, and what did you expect to happen? + validations: + required: true + - type: dropdown + id: version + attributes: + label: Version + description: What version of our Gophercloud are you running? + options: + - v2 (current) + - v1 (legacy) + - main (development) + default: 0 + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/rfe.yaml b/.github/ISSUE_TEMPLATE/rfe.yaml new file mode 100644 index 0000000000..41548cfb9c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/rfe.yaml @@ -0,0 +1,18 @@ +name: Feature request +description: Suggest an idea for this project. +title: "[RFE]: " +# type: Feature ## Not supported yet, despite docs saying otherwise: https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-issue-forms#top-level-syntax +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this enhancement request! Check out our [contributor guide](https://github.com/gophercloud/gophercloud/blob/main/docs/contributor-tutorial/step-02-issues.md) to create effective issues. + - type: textarea + id: what + attributes: + label: What is missing? + description: | + Is your feature request related to a problem? Please describe. Also feel free to describe the solution you'd like. + If you've found a missing field in an existing struct, please provide a link to the actual service's Python code which defines the missing field. + validations: + required: true diff --git a/.github/workflows/greetings.yaml b/.github/workflows/greetings.yaml deleted file mode 100644 index 72295f8965..0000000000 --- a/.github/workflows/greetings.yaml +++ /dev/null @@ -1,24 +0,0 @@ -name: Greetings - -on: [pull_request_target, issues] - -jobs: - greeting: - runs-on: ubuntu-latest - permissions: - issues: write - pull-requests: write - steps: - - uses: actions/first-interaction@v1 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - issue-message: | - Thank you for reporting your first issue! Be sure that we will be looking at it, but keep in mind - this sometimes takes a while. - Please let the maintainers know if your issue has not got enough attention after a few days. - If any doubt, please consult our issue [tutorial](https://github.com/gophercloud/gophercloud/blob/main/docs/contributor-tutorial/step-02-issues.md). - pr-message: | - Thank you for submitting your first PR! Be sure that we will be looking at it but keep in mind - this sometimes takes a while. - Please let the maintainers know if your PR has not got enough attention after a few days. - If any doubt, please consult our PR [tutorial](https://github.com/gophercloud/gophercloud/blob/main/docs/contributor-tutorial/step-05-pull-requests.md). From 9e5efb7546781a9e8296ed20cba02addc4fc61d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?p=C3=BDrus?= Date: Wed, 16 Jul 2025 13:42:15 +0200 Subject: [PATCH 227/429] core: clone service type aliases instead of referencing global slice --- endpoint_search.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/endpoint_search.go b/endpoint_search.go index e594dcb28e..e0a900f0f8 100644 --- a/endpoint_search.go +++ b/endpoint_search.go @@ -119,7 +119,7 @@ func (eo *EndpointOpts) ApplyDefaults(t string) { if len(eo.Aliases) == 0 { if aliases, ok := ServiceTypeAliases[eo.Type]; ok { // happy path: user requested a service type by its official name - eo.Aliases = aliases + eo.Aliases = slices.Clone(aliases) } else { // unhappy path: user requested a service type by its alias or an // invalid/unsupported service type @@ -129,7 +129,7 @@ func (eo *EndpointOpts) ApplyDefaults(t string) { // we intentionally override the service type, even if it // was explicitly requested by the user eo.Type = t - eo.Aliases = aliases + eo.Aliases = slices.Clone(aliases) } } } From 97368e998b835124e9367d9ed9327de9200f6982 Mon Sep 17 00:00:00 2001 From: Pierre Prinetti Date: Thu, 17 Jul 2025 09:37:40 +0200 Subject: [PATCH 228/429] Add issue type to issue template It seems supported now --- .github/ISSUE_TEMPLATE/bug.yaml | 3 +-- .github/ISSUE_TEMPLATE/rfe.yaml | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug.yaml b/.github/ISSUE_TEMPLATE/bug.yaml index 7aff19fe7d..b25d573119 100644 --- a/.github/ISSUE_TEMPLATE/bug.yaml +++ b/.github/ISSUE_TEMPLATE/bug.yaml @@ -1,7 +1,6 @@ name: Bug Report description: File a bug report. -title: "[Bug]: " -# type: Bug ## Not supported yet, despite docs saying otherwise: https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-issue-forms#top-level-syntax +type: Bug body: - type: markdown attributes: diff --git a/.github/ISSUE_TEMPLATE/rfe.yaml b/.github/ISSUE_TEMPLATE/rfe.yaml index 41548cfb9c..ab50e2b2ad 100644 --- a/.github/ISSUE_TEMPLATE/rfe.yaml +++ b/.github/ISSUE_TEMPLATE/rfe.yaml @@ -1,7 +1,6 @@ name: Feature request description: Suggest an idea for this project. -title: "[RFE]: " -# type: Feature ## Not supported yet, despite docs saying otherwise: https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-issue-forms#top-level-syntax +type: Feature body: - type: markdown attributes: From 6d9143e99f3c670c0eb86c74a18fdecda0f6bd45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?p=C3=BDrus?= Date: Fri, 18 Jul 2025 12:10:37 +0200 Subject: [PATCH 229/429] tests: shorten GH-A job names and use go-version-file: 'go.mod' for go version source --- .github/workflows/functional-baremetal.yaml | 5 +++-- .github/workflows/functional-basic.yaml | 5 +++-- .github/workflows/functional-blockstorage.yaml | 5 +++-- .github/workflows/functional-compute.yaml | 5 +++-- .github/workflows/functional-containerinfra.yaml | 5 +++-- .github/workflows/functional-dns.yaml | 5 +++-- .github/workflows/functional-fwaas_v2.yaml | 5 +++-- .github/workflows/functional-identity.yaml | 5 +++-- .github/workflows/functional-image.yaml | 5 +++-- .github/workflows/functional-keymanager.yaml | 5 +++-- .github/workflows/functional-loadbalancer.yaml | 5 +++-- .github/workflows/functional-messaging.yaml | 5 +++-- .github/workflows/functional-networking.yaml | 5 +++-- .github/workflows/functional-objectstorage.yaml | 5 +++-- .github/workflows/functional-orchestration.yaml | 5 +++-- .github/workflows/functional-placement.yaml | 5 +++-- .github/workflows/functional-sharedfilesystems.yaml | 5 +++-- .github/workflows/functional-workflow.yaml | 5 +++-- 18 files changed, 54 insertions(+), 36 deletions(-) diff --git a/.github/workflows/functional-baremetal.yaml b/.github/workflows/functional-baremetal.yaml index e67d9a8b86..8d562f0514 100644 --- a/.github/workflows/functional-baremetal.yaml +++ b/.github/workflows/functional-baremetal.yaml @@ -36,7 +36,7 @@ jobs: ubuntu_version: "22.04" additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} - name: Deploy OpenStack ${{ matrix.name }} with Ironic and run baremetal acceptance tests + name: Ironic on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud uses: actions/checkout@v4 @@ -84,7 +84,8 @@ jobs: - name: Checkout go uses: actions/setup-go@v5 with: - go-version: '^1.23' + go-version-file: 'go.mod' + cache: true - name: Run Gophercloud acceptance tests run: | source ${{ github.workspace }}/script/stackenv diff --git a/.github/workflows/functional-basic.yaml b/.github/workflows/functional-basic.yaml index 0269188b2e..562946a0da 100644 --- a/.github/workflows/functional-basic.yaml +++ b/.github/workflows/functional-basic.yaml @@ -31,7 +31,7 @@ jobs: ubuntu_version: "22.04" additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} - name: Deploy OpenStack ${{ matrix.name }} with defaults and run basic acceptance tests + name: basic tests on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud uses: actions/checkout@v4 @@ -43,7 +43,8 @@ jobs: - name: Checkout go uses: actions/setup-go@v5 with: - go-version: '^1.23' + go-version-file: 'go.mod' + cache: true - name: Run Gophercloud acceptance tests run: | source ${{ github.workspace }}/script/stackenv diff --git a/.github/workflows/functional-blockstorage.yaml b/.github/workflows/functional-blockstorage.yaml index 3616677505..2d2f33b981 100644 --- a/.github/workflows/functional-blockstorage.yaml +++ b/.github/workflows/functional-blockstorage.yaml @@ -36,7 +36,7 @@ jobs: ubuntu_version: "22.04" additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} - name: Deploy OpenStack ${{ matrix.name }} with Cinder and run blockstorage acceptance tests + name: Cinder on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud uses: actions/checkout@v4 @@ -50,7 +50,8 @@ jobs: - name: Checkout go uses: actions/setup-go@v5 with: - go-version: '^1.23' + go-version-file: 'go.mod' + cache: true - name: Run Gophercloud acceptance tests run: | source ${{ github.workspace }}/script/stackenv diff --git a/.github/workflows/functional-compute.yaml b/.github/workflows/functional-compute.yaml index b31f319fbc..c347d93e74 100644 --- a/.github/workflows/functional-compute.yaml +++ b/.github/workflows/functional-compute.yaml @@ -36,7 +36,7 @@ jobs: ubuntu_version: "22.04" additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} - name: Deploy OpenStack ${{ matrix.name }} with Nova and run compute acceptance tests + name: Nova on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud uses: actions/checkout@v4 @@ -50,7 +50,8 @@ jobs: - name: Checkout go uses: actions/setup-go@v5 with: - go-version: '^1.23' + go-version-file: 'go.mod' + cache: true - name: Run Gophercloud acceptance tests run: | source ${{ github.workspace }}/script/stackenv diff --git a/.github/workflows/functional-containerinfra.yaml b/.github/workflows/functional-containerinfra.yaml index 1eba68df9d..1239962b0c 100644 --- a/.github/workflows/functional-containerinfra.yaml +++ b/.github/workflows/functional-containerinfra.yaml @@ -60,7 +60,7 @@ jobs: MAGNUMCLIENT_BRANCH=stable/2024.1 additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} - name: Deploy OpenStack ${{ matrix.name }} with Magnum and run containerinfra acceptance tests + name: Magnum on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud uses: actions/checkout@v4 @@ -80,7 +80,8 @@ jobs: - name: Checkout go uses: actions/setup-go@v5 with: - go-version: '^1.23' + go-version-file: 'go.mod' + cache: true - name: Run Gophercloud acceptance tests run: | source ${{ github.workspace }}/script/stackenv diff --git a/.github/workflows/functional-dns.yaml b/.github/workflows/functional-dns.yaml index 8f405ada85..042ab75fca 100644 --- a/.github/workflows/functional-dns.yaml +++ b/.github/workflows/functional-dns.yaml @@ -42,7 +42,7 @@ jobs: ubuntu_version: "22.04" additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} - name: Deploy OpenStack ${{ matrix.name }} with Designate and run dns acceptance tests + name: Designate on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud uses: actions/checkout@v4 @@ -58,7 +58,8 @@ jobs: - name: Checkout go uses: actions/setup-go@v5 with: - go-version: '^1.23' + go-version-file: 'go.mod' + cache: true - name: Run Gophercloud acceptance tests run: | source ${{ github.workspace }}/script/stackenv diff --git a/.github/workflows/functional-fwaas_v2.yaml b/.github/workflows/functional-fwaas_v2.yaml index d2596ee780..bda886c68b 100644 --- a/.github/workflows/functional-fwaas_v2.yaml +++ b/.github/workflows/functional-fwaas_v2.yaml @@ -40,7 +40,7 @@ jobs: ubuntu_version: "22.04" additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} - name: Deploy OpenStack ${{ matrix.name }} with enabled FWaaS_v2 and run networking acceptance tests + name: FWaaS_v2 on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud uses: actions/checkout@v4 @@ -71,7 +71,8 @@ jobs: - name: Checkout go uses: actions/setup-go@v5 with: - go-version: '^1.23' + go-version-file: 'go.mod' + cache: true - name: Run Gophercloud acceptance tests run: | source ${{ github.workspace }}/script/stackenv diff --git a/.github/workflows/functional-identity.yaml b/.github/workflows/functional-identity.yaml index daf5195daf..0db81b6f85 100644 --- a/.github/workflows/functional-identity.yaml +++ b/.github/workflows/functional-identity.yaml @@ -36,7 +36,7 @@ jobs: ubuntu_version: "22.04" additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} - name: Deploy OpenStack ${{ matrix.name }} with Keystone and run identity acceptance tests + name: Keystone on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud uses: actions/checkout@v4 @@ -48,7 +48,8 @@ jobs: - name: Checkout go uses: actions/setup-go@v5 with: - go-version: '^1.23' + go-version-file: 'go.mod' + cache: true - name: Run Gophercloud acceptance tests run: | source ${{ github.workspace }}/script/stackenv diff --git a/.github/workflows/functional-image.yaml b/.github/workflows/functional-image.yaml index 1e0075411c..6e6e884739 100644 --- a/.github/workflows/functional-image.yaml +++ b/.github/workflows/functional-image.yaml @@ -36,7 +36,7 @@ jobs: ubuntu_version: "22.04" additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} - name: Deploy OpenStack ${{ matrix.name }} with Glance and run image acceptance tests + name: Glance on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud uses: actions/checkout@v4 @@ -48,7 +48,8 @@ jobs: - name: Checkout go uses: actions/setup-go@v5 with: - go-version: '^1.23' + go-version-file: 'go.mod' + cache: true - name: Run Gophercloud acceptance tests run: | source ${{ github.workspace }}/script/stackenv diff --git a/.github/workflows/functional-keymanager.yaml b/.github/workflows/functional-keymanager.yaml index 2dc6fb9133..04016bba41 100644 --- a/.github/workflows/functional-keymanager.yaml +++ b/.github/workflows/functional-keymanager.yaml @@ -48,7 +48,7 @@ jobs: ubuntu_version: "22.04" additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} - name: Deploy OpenStack ${{ matrix.name }} with Barbican and run keymanager acceptance tests + name: Barbican on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud uses: actions/checkout@v4 @@ -64,7 +64,8 @@ jobs: - name: Checkout go uses: actions/setup-go@v5 with: - go-version: '^1.23' + go-version-file: 'go.mod' + cache: true - name: Run Gophercloud acceptance tests run: | source ${{ github.workspace }}/script/stackenv diff --git a/.github/workflows/functional-loadbalancer.yaml b/.github/workflows/functional-loadbalancer.yaml index e93f751a8b..ff35ede770 100644 --- a/.github/workflows/functional-loadbalancer.yaml +++ b/.github/workflows/functional-loadbalancer.yaml @@ -42,7 +42,7 @@ jobs: ubuntu_version: "22.04" additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} - name: Deploy OpenStack ${{ matrix.name }} with Octavia and run loadbalancer acceptance tests + name: Octavia on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud uses: actions/checkout@v4 @@ -59,7 +59,8 @@ jobs: - name: Checkout go uses: actions/setup-go@v5 with: - go-version: '^1.23' + go-version-file: 'go.mod' + cache: true - name: Run Gophercloud acceptance tests run: | source ${{ github.workspace }}/script/stackenv diff --git a/.github/workflows/functional-messaging.yaml b/.github/workflows/functional-messaging.yaml index 6c9688483b..ee54f43050 100644 --- a/.github/workflows/functional-messaging.yaml +++ b/.github/workflows/functional-messaging.yaml @@ -36,7 +36,7 @@ jobs: ubuntu_version: "22.04" additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} - name: Deploy OpenStack ${{ matrix.name }} with Zaqar and run messaging acceptance tests + name: Zaqar on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud uses: actions/checkout@v4 @@ -51,7 +51,8 @@ jobs: - name: Checkout go uses: actions/setup-go@v5 with: - go-version: '^1.23' + go-version-file: 'go.mod' + cache: true - name: Run Gophercloud acceptance tests run: | source ${{ github.workspace }}/script/stackenv diff --git a/.github/workflows/functional-networking.yaml b/.github/workflows/functional-networking.yaml index 742a1c9dfc..d07bcce7f5 100644 --- a/.github/workflows/functional-networking.yaml +++ b/.github/workflows/functional-networking.yaml @@ -36,7 +36,7 @@ jobs: ubuntu_version: "22.04" additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} - name: Deploy OpenStack ${{ matrix.name }} with Neutron and run networking acceptance tests + name: Neutron on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud uses: actions/checkout@v4 @@ -66,7 +66,8 @@ jobs: - name: Checkout go uses: actions/setup-go@v5 with: - go-version: '^1.23' + go-version-file: 'go.mod' + cache: true - name: Run Gophercloud acceptance tests run: | source ${{ github.workspace }}/script/stackenv diff --git a/.github/workflows/functional-objectstorage.yaml b/.github/workflows/functional-objectstorage.yaml index 61a128a5dc..3797c2cdcb 100644 --- a/.github/workflows/functional-objectstorage.yaml +++ b/.github/workflows/functional-objectstorage.yaml @@ -36,7 +36,7 @@ jobs: ubuntu_version: "22.04" additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} - name: Deploy OpenStack ${{ matrix.name }} with Swift and run objectstorage acceptance tests + name: Swift on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud uses: actions/checkout@v4 @@ -54,7 +54,8 @@ jobs: - name: Checkout go uses: actions/setup-go@v5 with: - go-version: '^1.23' + go-version-file: 'go.mod' + cache: true - name: Run Gophercloud acceptance tests run: | source ${{ github.workspace }}/script/stackenv diff --git a/.github/workflows/functional-orchestration.yaml b/.github/workflows/functional-orchestration.yaml index 3fae34a1fe..930e31ba63 100644 --- a/.github/workflows/functional-orchestration.yaml +++ b/.github/workflows/functional-orchestration.yaml @@ -36,7 +36,7 @@ jobs: ubuntu_version: "22.04" additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} - name: Deploy OpenStack ${{ matrix.name }} with Heat and run orchestration acceptance tests + name: Heat on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud uses: actions/checkout@v4 @@ -50,7 +50,8 @@ jobs: - name: Checkout go uses: actions/setup-go@v5 with: - go-version: '^1.23' + go-version-file: 'go.mod' + cache: true - name: Run Gophercloud acceptance tests run: | source ${{ github.workspace }}/script/stackenv diff --git a/.github/workflows/functional-placement.yaml b/.github/workflows/functional-placement.yaml index 4a578fcbad..43dd35ea72 100644 --- a/.github/workflows/functional-placement.yaml +++ b/.github/workflows/functional-placement.yaml @@ -36,7 +36,7 @@ jobs: ubuntu_version: "22.04" additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} - name: Deploy OpenStack ${{ matrix.name }} with Placement and run placement acceptance tests + name: Placement on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud uses: actions/checkout@v4 @@ -48,7 +48,8 @@ jobs: - name: Checkout go uses: actions/setup-go@v5 with: - go-version: '^1.23' + go-version-file: 'go.mod' + cache: true - name: Run Gophercloud acceptance tests run: | source ${{ github.workspace }}/script/stackenv diff --git a/.github/workflows/functional-sharedfilesystems.yaml b/.github/workflows/functional-sharedfilesystems.yaml index 4700807969..8fbc3e3d2b 100644 --- a/.github/workflows/functional-sharedfilesystems.yaml +++ b/.github/workflows/functional-sharedfilesystems.yaml @@ -42,7 +42,7 @@ jobs: ubuntu_version: "22.04" additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} - name: Deploy OpenStack ${{ matrix.name }} with Manila and run sharedfilesystems acceptance tests + name: Manila on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud uses: actions/checkout@v4 @@ -72,7 +72,8 @@ jobs: - name: Checkout go uses: actions/setup-go@v5 with: - go-version: '^1.23' + go-version-file: 'go.mod' + cache: true - name: Run Gophercloud acceptance tests run: | source ${{ github.workspace }}/script/stackenv diff --git a/.github/workflows/functional-workflow.yaml b/.github/workflows/functional-workflow.yaml index 2dbd86db07..5fad4cec42 100644 --- a/.github/workflows/functional-workflow.yaml +++ b/.github/workflows/functional-workflow.yaml @@ -40,7 +40,7 @@ jobs: mistral_plugin_version: "stable/2024.1" additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} - name: Deploy OpenStack ${{ matrix.name }} with Mistral and run workflow acceptance tests + name: Mistral on Deploy OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud uses: actions/checkout@v4 @@ -54,7 +54,8 @@ jobs: - name: Checkout go uses: actions/setup-go@v5 with: - go-version: '^1.23' + go-version-file: 'go.mod' + cache: true - name: Run Gophercloud acceptance tests run: | source ${{ github.workspace }}/script/stackenv From e652773b28535f90ee0efd83521f638971d7f38f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?p=C3=BDrus?= Date: Fri, 18 Jul 2025 12:23:43 +0200 Subject: [PATCH 230/429] tests: use go.mod as a version source in other workflows --- .github/workflows/codeql-analysis.yaml | 9 +++++---- .github/workflows/lint.yaml | 4 +--- .github/workflows/unit.yaml | 11 +++-------- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/.github/workflows/codeql-analysis.yaml b/.github/workflows/codeql-analysis.yaml index a9695c7cff..8efeaf761c 100644 --- a/.github/workflows/codeql-analysis.yaml +++ b/.github/workflows/codeql-analysis.yaml @@ -17,13 +17,14 @@ jobs: language: [ 'go' ] steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Setup Go uses: actions/setup-go@v5 with: - go-version: "1.23" - - - name: Checkout repository - uses: actions/checkout@v4 + go-version-file: 'go.mod' + cache: true - name: Initialize CodeQL uses: github/codeql-action/init@v3 diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index ed7399819d..be44ea86bc 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -16,8 +16,6 @@ jobs: - name: Run linters run: | make lint - # TODO: Use 'go mod tidy -diff' instead once go 1.23 is out - # https://github.com/golang/go/issues/27005 - name: Ensure go.mod is up-to-date run: | - if [ $(go mod tidy && git diff | wc -l) -gt 0 ]; then git diff && exit 1; fi + if [ $(go mod tidy -diff | wc -l) -gt 0 ]; then git diff && exit 1; fi diff --git a/.github/workflows/unit.yaml b/.github/workflows/unit.yaml index ab11e26561..140e64fbed 100644 --- a/.github/workflows/unit.yaml +++ b/.github/workflows/unit.yaml @@ -12,17 +12,14 @@ jobs: runs-on: ubuntu-latest strategy: fail-fast: false - matrix: - go-version: - - "1.23.0" - - "1" steps: - name: Checkout Gophercloud uses: actions/checkout@v4 - - name: Setup Go ${{ matrix.go-version }} + - name: Setup Go uses: actions/setup-go@v5 with: - go-version: ${{ matrix.go-version }} + go-version-file: 'go.mod' + cache: true - name: Setup environment run: | # Changing into a different directory to avoid polluting go.sum with "go get" @@ -37,7 +34,6 @@ jobs: uses: coverallsapp/github-action@v2 with: file: cover.out - flag-name: Go-${{ matrix.go-version }} parallel: true finish: permissions: @@ -50,4 +46,3 @@ jobs: uses: coverallsapp/github-action@v2 with: parallel-finished: true - carryforward: Go-${{ join(matrix.go-version.*, '-') }} From b9132fc208fb20e16e4b2785e3ff8dba19b84996 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Mon, 10 Mar 2025 09:46:12 +0100 Subject: [PATCH 231/429] Switch to a version of gocovmerge compatible with go 1.22 The original `gocovmerge` repository [1] has not seen a commit in 9 years and should be considered unmaintained. Switch to fork has a go.mod pinned to go 1.22. Please review the diff [2] between the two repos to check if it's safe to use in gophercloud. [1] https://github.com/wadey/gocovmerge [2] https://github.com/wadey/gocovmerge/compare/master...alexfalkowski:gocovmerge:v1.4.0 --- .github/workflows/unit.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/unit.yaml b/.github/workflows/unit.yaml index 140e64fbed..ae3b2f0059 100644 --- a/.github/workflows/unit.yaml +++ b/.github/workflows/unit.yaml @@ -25,7 +25,7 @@ jobs: # Changing into a different directory to avoid polluting go.sum with "go get" cd "$(mktemp -d)" go mod init unit_tests - go install github.com/wadey/gocovmerge@master + go install github.com/alexfalkowski/gocovmerge@v1.4.0 - name: Run unit tests run: | make unit From 4b7e159b3c5b2181a10d15c5644d99f37af02a0d Mon Sep 17 00:00:00 2001 From: Fabian Wiesel Date: Mon, 21 Jul 2025 15:07:25 +0200 Subject: [PATCH 232/429] Change compute services UpdateOpts fields ForceDown to pointer This follows the same pattern as in the rest of the code and uses a pointer to fix #3471 and allow the caller to unset a prior ForceDown. This unfortunately changes though the API in a breaking way. --- openstack/compute/v2/services/requests.go | 2 +- .../v2/services/testing/fixtures_test.go | 57 +++++++++++++++++++ .../v2/services/testing/requests_test.go | 30 ++++++++++ 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/openstack/compute/v2/services/requests.go b/openstack/compute/v2/services/requests.go index 32be17cb70..6fce69eb15 100644 --- a/openstack/compute/v2/services/requests.go +++ b/openstack/compute/v2/services/requests.go @@ -67,7 +67,7 @@ type UpdateOpts struct { // ForcedDown is a manual override to tell nova that the service in question // has been fenced manually by the operations team. - ForcedDown bool `json:"forced_down,omitempty"` + ForcedDown *bool `json:"forced_down,omitempty"` } // ToServiceUpdateMap formats an UpdateOpts structure into a request body. diff --git a/openstack/compute/v2/services/testing/fixtures_test.go b/openstack/compute/v2/services/testing/fixtures_test.go index 47e549e1b3..2a17d7d120 100644 --- a/openstack/compute/v2/services/testing/fixtures_test.go +++ b/openstack/compute/v2/services/testing/fixtures_test.go @@ -238,6 +238,23 @@ const ServiceUpdate = ` } ` +const ServiceUpdateForceDown = ` +{ + "service": + { + "id": 1, + "binary": "nova-scheduler", + "disabled_reason": "test1", + "host": "host1", + "state": "up", + "status": "disabled", + "updated_at": "2012-10-29T13:42:02.000000", + "forced_down": true, + "zone": "internal" + } +} +` + // FakeServiceUpdateBody represents the updated service var FakeServiceUpdateBody = services.Service{ Binary: "nova-scheduler", @@ -251,6 +268,18 @@ var FakeServiceUpdateBody = services.Service{ Zone: "internal", } +var FakeServiceUpdateForceDownBody = services.Service{ + Binary: "nova-scheduler", + DisabledReason: "test1", + ForcedDown: true, + Host: "host1", + ID: "1", + State: "up", + Status: "disabled", + UpdatedAt: time.Date(2012, 10, 29, 13, 42, 2, 0, time.UTC), + Zone: "internal", +} + // HandleListPre253Successfully configures the test server to respond to a List // request to a Compute server API pre 2.53 microversion release. func HandleListPre253Successfully(t *testing.T, fakeServer th.FakeServer) { @@ -289,6 +318,34 @@ func HandleUpdateSuccessfully(t *testing.T, fakeServer th.FakeServer) { }) } +// HandleForceDownSuccessfully configures the test server to respond to a Update +// request to a Compute server with Pike+ release. +func HandleForceDownSuccessfully(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/os-services/fake-service-id", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "PUT") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.TestHeader(t, r, "Accept", "application/json") + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestJSONRequest(t, r, `{"forced_down": true}`) + + fmt.Fprint(w, ServiceUpdateForceDown) + }) +} + +// HandleDisableForceDownSuccessfully configures the test server to respond to a Update +// request to a Compute server with Pike+ release. +func HandleDisableForceDownSuccessfully(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/os-services/fake-service-id", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "PUT") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.TestHeader(t, r, "Accept", "application/json") + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestJSONRequest(t, r, `{"forced_down": false}`) + + fmt.Fprint(w, ServiceUpdate) + }) +} + // HandleDeleteSuccessfully configures the test server to respond to a Delete // request to a Compute server with Pike+ release. func HandleDeleteSuccessfully(t *testing.T, fakeServer th.FakeServer) { diff --git a/openstack/compute/v2/services/testing/requests_test.go b/openstack/compute/v2/services/testing/requests_test.go index 3fac76abfe..d92d7d209e 100644 --- a/openstack/compute/v2/services/testing/requests_test.go +++ b/openstack/compute/v2/services/testing/requests_test.go @@ -92,6 +92,36 @@ func TestUpdateService(t *testing.T) { th.CheckDeepEquals(t, FakeServiceUpdateBody, *actual) } +func TestUpdateServiceForceDown(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + HandleForceDownSuccessfully(t, fakeServer) + + client := client.ServiceClient(fakeServer) + trueVal := true + actual, err := services.Update(context.TODO(), client, "fake-service-id", services.UpdateOpts{ForcedDown: &trueVal}).Extract() + if err != nil { + t.Fatalf("Unexpected Update error: %v", err) + } + + th.CheckDeepEquals(t, FakeServiceUpdateForceDownBody, *actual) +} + +func TestUpdateServiceDisableForceDown(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + HandleDisableForceDownSuccessfully(t, fakeServer) + + client := client.ServiceClient(fakeServer) + falseVal := false + actual, err := services.Update(context.TODO(), client, "fake-service-id", services.UpdateOpts{ForcedDown: &falseVal}).Extract() + if err != nil { + t.Fatalf("Unexpected Update error: %v", err) + } + + th.CheckDeepEquals(t, FakeServiceUpdateBody, *actual) +} + func TestDeleteService(t *testing.T) { fakeServer := th.SetupHTTP() defer fakeServer.Teardown() From 8e2cf7ede225d90a1a3f642cbb16516922c882fd Mon Sep 17 00:00:00 2001 From: Fabian Wiesel Date: Tue, 22 Jul 2025 10:19:18 +0200 Subject: [PATCH 233/429] Implement update & delete traits on resource provider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This implements #2420. The relevant server side code can be found here: https://github.com/openstack/placement/blob/stable/2025.1/placement/handlers/trait.py#L216-L274 Co-authored-by: pýrus --- .../v1/resourceproviders/requests.go | 35 +++++++++++++++++++ .../testing/fixtures_test.go | 26 ++++++++++++++ .../testing/requests_test.go | 22 ++++++++++++ 3 files changed, 83 insertions(+) diff --git a/openstack/placement/v1/resourceproviders/requests.go b/openstack/placement/v1/resourceproviders/requests.go index 5c5075e445..f0dfa9d66f 100644 --- a/openstack/placement/v1/resourceproviders/requests.go +++ b/openstack/placement/v1/resourceproviders/requests.go @@ -175,3 +175,38 @@ func GetTraits(ctx context.Context, client *gophercloud.ServiceClient, resourceP _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return } + +// UpdateTraitsOptsBuilder allows extensions to add additional parameters to the +// UpdateTraits request. +type UpdateTraitsOptsBuilder interface { + ToResourceProviderUpdateTraitsMap() (map[string]any, error) +} + +// UpdateTraitsOpts represents options used to update traits of a resource provider. +type UpdateTraitsOpts = ResourceProviderTraits + +// ToResourceProviderUpdateTraitsMap constructs a request body from UpdateTraitsOpts. +func (opts UpdateTraitsOpts) ToResourceProviderUpdateTraitsMap() (map[string]any, error) { + return gophercloud.BuildRequestBody(opts, "") +} + +func UpdateTraits(ctx context.Context, client *gophercloud.ServiceClient, resourceProviderID string, opts UpdateTraitsOptsBuilder) (r GetTraitsResult) { + b, err := opts.ToResourceProviderUpdateTraitsMap() + if err != nil { + r.Err = err + return + } + resp, err := client.Put(ctx, getResourceProviderTraitsURL(client, resourceProviderID), b, &r.Body, &gophercloud.RequestOpts{ + OkCodes: []int{200}, + }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + +func DeleteTraits(ctx context.Context, client *gophercloud.ServiceClient, resourceProviderID string) (r DeleteResult) { + resp, err := client.Delete(ctx, getResourceProviderTraitsURL(client, resourceProviderID), &gophercloud.RequestOpts{ + OkCodes: []int{204}, + }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} diff --git a/openstack/placement/v1/resourceproviders/testing/fixtures_test.go b/openstack/placement/v1/resourceproviders/testing/fixtures_test.go index 7ddc91b240..6ac4b8ca73 100644 --- a/openstack/placement/v1/resourceproviders/testing/fixtures_test.go +++ b/openstack/placement/v1/resourceproviders/testing/fixtures_test.go @@ -387,3 +387,29 @@ func HandleResourceProviderGetTraits(t *testing.T, fakeServer th.FakeServer) { fmt.Fprint(w, TraitsBody) }) } + +func HandleResourceProviderPutTraits(t *testing.T, fakeServer th.FakeServer) { + traitsTestUrl := fmt.Sprintf("/resource_providers/%s/traits", ResourceProviderTestID) + + fakeServer.Mux.HandleFunc(traitsTestUrl, + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "PUT") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, TraitsBody) + }) +} + +func HandleResourceProviderDeleteTraits(t *testing.T, fakeServer th.FakeServer) { + traitsTestUrl := fmt.Sprintf("/resource_providers/%s/traits", ResourceProviderTestID) + + fakeServer.Mux.HandleFunc(traitsTestUrl, + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "DELETE") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + w.WriteHeader(http.StatusNoContent) + }) +} diff --git a/openstack/placement/v1/resourceproviders/testing/requests_test.go b/openstack/placement/v1/resourceproviders/testing/requests_test.go index 1336126ecb..4633c81136 100644 --- a/openstack/placement/v1/resourceproviders/testing/requests_test.go +++ b/openstack/placement/v1/resourceproviders/testing/requests_test.go @@ -145,3 +145,25 @@ func TestGetResourceProvidersTraits(t *testing.T) { th.AssertNoErr(t, err) th.AssertDeepEquals(t, ExpectedTraits, *actual) } + +func TestUpdateResourceProvidersTraits(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleResourceProviderPutTraits(t, fakeServer) + + opts := resourceproviders.UpdateTraitsOpts(ExpectedTraits) + actual, err := resourceproviders.UpdateTraits(context.TODO(), client.ServiceClient(fakeServer), ResourceProviderTestID, opts).Extract() + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedTraits, *actual) +} + +func TestDeleteResourceProvidersTraits(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleResourceProviderDeleteTraits(t, fakeServer) + + err := resourceproviders.DeleteTraits(context.TODO(), client.ServiceClient(fakeServer), ResourceProviderTestID).ExtractErr() + th.AssertNoErr(t, err) +} From 440ef87e6581c404fec36b0c0066f116b9a55373 Mon Sep 17 00:00:00 2001 From: Amir Aslan Aslan Date: Sat, 26 Jul 2025 14:34:06 +0330 Subject: [PATCH 234/429] fix: correct comment for PortRangeMax in CreateOpts to specify ICMP code --- openstack/networking/v2/extensions/security/rules/requests.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openstack/networking/v2/extensions/security/rules/requests.go b/openstack/networking/v2/extensions/security/rules/requests.go index 1cba0624bb..c691059b42 100644 --- a/openstack/networking/v2/extensions/security/rules/requests.go +++ b/openstack/networking/v2/extensions/security/rules/requests.go @@ -125,7 +125,7 @@ type CreateOpts struct { // The maximum port number in the range that is matched by the security group // rule. The PortRangeMin attribute constrains the PortRangeMax attribute. If - // the protocol is ICMP, this value must be an ICMP type. + // the protocol is ICMP, this value must be an ICMP code. PortRangeMax int `json:"port_range_max,omitempty"` // The minimum port number in the range that is matched by the security group From f3d2128b861d4bbd70d29ae341e9d8efcff4105c Mon Sep 17 00:00:00 2001 From: Fabian Wiesel Date: Thu, 31 Jul 2025 12:34:18 +0200 Subject: [PATCH 235/429] Implement hypervisors.GetExt: Get with Query parameter This introduces a new function GetExt in order to avoid breaking backwards compatibility. Implements #3479 --- openstack/compute/v2/hypervisors/requests.go | 35 ++++- .../v2/hypervisors/testing/fixtures_test.go | 120 ++++++++++++++++++ .../v2/hypervisors/testing/requests_test.go | 12 ++ 3 files changed, 166 insertions(+), 1 deletion(-) diff --git a/openstack/compute/v2/hypervisors/requests.go b/openstack/compute/v2/hypervisors/requests.go index b17dd35781..2483d73407 100644 --- a/openstack/compute/v2/hypervisors/requests.go +++ b/openstack/compute/v2/hypervisors/requests.go @@ -66,9 +66,42 @@ func GetStatistics(ctx context.Context, client *gophercloud.ServiceClient) (r St return } +// GetOptsBuilder allows extensions to add additional parameters to the +// Get request. +type GetOptsBuilder interface { + ToHypervisorGetQuery() (string, error) +} + +// GetOpts allows the opt-in to add the servers to the response +type GetOpts struct { + // WithServers is a bool to include all servers which belong to the hypervisor + // This requires microversion 2.53 or later + WithServers *bool `q:"with_servers"` +} + +// ToHypervisorGetQuery formats a GetOpts into a query string. +func (opts GetOpts) ToHypervisorGetQuery() (string, error) { + q, err := gophercloud.BuildQueryString(opts) + return q.String(), err +} + // Get makes a request against the API to get details for specific hypervisor. func Get(ctx context.Context, client *gophercloud.ServiceClient, hypervisorID string) (r HypervisorResult) { - resp, err := client.Get(ctx, hypervisorsGetURL(client, hypervisorID), &r.Body, &gophercloud.RequestOpts{ + return GetExt(ctx, client, hypervisorID, nil) +} + +// Show makes a request against the API to get details for specific hypervisor with optional query parameters +func GetExt(ctx context.Context, client *gophercloud.ServiceClient, hypervisorID string, opts GetOptsBuilder) (r HypervisorResult) { + url := hypervisorsGetURL(client, hypervisorID) + if opts != nil { + query, err := opts.ToHypervisorGetQuery() + if err != nil { + return HypervisorResult{gophercloud.Result{Err: err}} + } + url += query + } + + resp, err := client.Get(ctx, url, &r.Body, &gophercloud.RequestOpts{ OkCodes: []int{200}, }) _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) diff --git a/openstack/compute/v2/hypervisors/testing/fixtures_test.go b/openstack/compute/v2/hypervisors/testing/fixtures_test.go index ebfd816c03..166c415106 100644 --- a/openstack/compute/v2/hypervisors/testing/fixtures_test.go +++ b/openstack/compute/v2/hypervisors/testing/fixtures_test.go @@ -329,6 +329,62 @@ const HypervisorGetBody = ` } ` +// HypervisorGetPost253Body represents a raw hypervisor GET result with Pike+ +// release with optional server list +const HypervisorGetPost253Body = ` +{ + "hypervisor":{ + "cpu_info":{ + "arch":"x86_64", + "model":"Nehalem", + "vendor":"Intel", + "features":[ + "pge", + "clflush" + ], + "topology":{ + "cores":1, + "threads":1, + "sockets":4 + } + }, + "current_workload":0, + "status":"enabled", + "state":"up", + "servers": [ + { + "name": "test_server1", + "uuid": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" + }, + { + "name": "test_server2", + "uuid": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb" + } + ], + "disk_available_least":0, + "host_ip":"1.1.1.1", + "free_disk_gb":1028, + "free_ram_mb":7680, + "hypervisor_hostname":"fake-mini", + "hypervisor_type":"fake", + "hypervisor_version":2002000, + "id":"c48f6247-abe4-4a24-824e-ea39e108874f", + "local_gb":1028, + "local_gb_used":0, + "memory_mb":8192, + "memory_mb_used":512, + "running_vms":2, + "service":{ + "host":"e6a37ee802d74863ab8b91ade8f12a67", + "id":"9c2566e7-7a54-4777-a1ae-c2662f0c407c", + "disabled_reason":null + }, + "vcpus":1, + "vcpus_used":0 + } +} +` + // HypervisorGetEmptyCPUInfoBody represents a raw hypervisor GET result with // no cpu_info const HypervisorGetEmptyCPUInfoBody = ` @@ -487,6 +543,56 @@ var ( VCPUsUsed: 0, } + HypervisorFakeWithServers = hypervisors.Hypervisor{ + CPUInfo: hypervisors.CPUInfo{ + Arch: "x86_64", + Model: "Nehalem", + Vendor: "Intel", + Features: []string{ + "pge", + "clflush", + }, + Topology: hypervisors.Topology{ + Cores: 1, + Threads: 1, + Sockets: 4, + }, + }, + CurrentWorkload: 0, + Status: "enabled", + State: "up", + Servers: &[]hypervisors.Server{ + { + Name: "test_server1", + UUID: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", + }, + { + Name: "test_server2", + UUID: "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb", + }, + }, + DiskAvailableLeast: 0, + HostIP: "1.1.1.1", + FreeDiskGB: 1028, + FreeRamMB: 7680, + HypervisorHostname: "fake-mini", + HypervisorType: "fake", + HypervisorVersion: 2002000, + ID: "c48f6247-abe4-4a24-824e-ea39e108874f", + LocalGB: 1028, + LocalGBUsed: 0, + MemoryMB: 8192, + MemoryMBUsed: 512, + RunningVMs: 2, + Service: hypervisors.Service{ + Host: "e6a37ee802d74863ab8b91ade8f12a67", + ID: "9c2566e7-7a54-4777-a1ae-c2662f0c407c", + DisabledReason: "", + }, + VCPUs: 1, + VCPUsUsed: 0, + } + HypervisorFakeWithParameters = hypervisors.Hypervisor{ CPUInfo: hypervisors.CPUInfo{ Arch: "x86_64", @@ -676,6 +782,20 @@ func HandleHypervisorGetSuccessfully(t *testing.T, fakeServer th.FakeServer) { }) } +func HandleHypervisorGetPost253Successfully(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/os-hypervisors/"+HypervisorFake.ID, func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + if r.URL.Query().Get("with_servers") == "true" { + fmt.Fprint(w, HypervisorGetPost253Body) + } else { + fmt.Fprint(w, HypervisorGetBody) + } + }) +} + func HandleHypervisorGetEmptyCPUInfoSuccessfully(t *testing.T, fakeServer th.FakeServer) { fakeServer.Mux.HandleFunc("/os-hypervisors/"+HypervisorFake.ID, func(w http.ResponseWriter, r *http.Request) { th.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 a2b2183e48..c6c7d9141f 100644 --- a/openstack/compute/v2/hypervisors/testing/requests_test.go +++ b/openstack/compute/v2/hypervisors/testing/requests_test.go @@ -135,6 +135,18 @@ func TestGetHypervisor(t *testing.T) { th.CheckDeepEquals(t, &expected, actual) } +func TestGetWithServersHypervisor(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + HandleHypervisorGetPost253Successfully(t, fakeServer) + + expected := HypervisorFakeWithServers + withServers := true + actual, err := hypervisors.GetExt(context.TODO(), client.ServiceClient(fakeServer), expected.ID, hypervisors.GetOpts{WithServers: &withServers}).Extract() + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, &expected, actual) +} + func TestGetHypervisorEmptyCPUInfo(t *testing.T) { fakeServer := th.SetupHTTP() defer fakeServer.Teardown() From 38c1bcac0998926568a75ece4b885ae8df4e953b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zden=C4=9Bk=20Vydra?= <80331839+vydrazde@users.noreply.github.com> Date: Wed, 6 Aug 2025 13:12:35 +0200 Subject: [PATCH 236/429] Add networking taas tapmirror create --- .../networking/v2/extensions/taas/taas.go | 44 +++++++++ .../v2/extensions/taas/tapmirrors_test.go | 39 ++++++++ .../v2/extensions/taas/tapmirrors/doc.go | 23 +++++ .../v2/extensions/taas/tapmirrors/requests.go | 67 ++++++++++++++ .../v2/extensions/taas/tapmirrors/results.go | 69 ++++++++++++++ .../taas/tapmirrors/testing/requests_test.go | 91 +++++++++++++++++++ .../v2/extensions/taas/tapmirrors/urls.go | 12 +++ 7 files changed, 345 insertions(+) create mode 100644 internal/acceptance/openstack/networking/v2/extensions/taas/taas.go create mode 100644 internal/acceptance/openstack/networking/v2/extensions/taas/tapmirrors_test.go create mode 100644 openstack/networking/v2/extensions/taas/tapmirrors/doc.go create mode 100644 openstack/networking/v2/extensions/taas/tapmirrors/requests.go create mode 100644 openstack/networking/v2/extensions/taas/tapmirrors/results.go create mode 100644 openstack/networking/v2/extensions/taas/tapmirrors/testing/requests_test.go create mode 100644 openstack/networking/v2/extensions/taas/tapmirrors/urls.go diff --git a/internal/acceptance/openstack/networking/v2/extensions/taas/taas.go b/internal/acceptance/openstack/networking/v2/extensions/taas/taas.go new file mode 100644 index 0000000000..026c5d2292 --- /dev/null +++ b/internal/acceptance/openstack/networking/v2/extensions/taas/taas.go @@ -0,0 +1,44 @@ +package taas + +import ( + "context" + "strconv" + "testing" + + "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" + "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/taas/tapmirrors" + th "github.com/gophercloud/gophercloud/v2/testhelper" +) + +// CreateTapMirror will create a Tap Mirror with the specified portID and remoteIP. An error +// will be returned if the Tap Mirror could not be created. +func CreateTapMirror(t *testing.T, client *gophercloud.ServiceClient, portID string, remoteIP string) (*tapmirrors.TapMirror, error) { + mirrorName := tools.RandomString("TESTACC-", 8) + mirrorDescription := tools.RandomString("TESTACC-DESC-", 8) + mirrorDirectionIN := tools.RandomInt(1, 1000000) + t.Logf("Attempting to create tap mirror: %s", mirrorName) + + createopts := tapmirrors.CreateOpts{ + Name: mirrorName, + Description: mirrorDescription, + PortID: portID, + MirrorType: tapmirrors.MirrorTypeErspanv1, + RemoteIP: remoteIP, + Directions: tapmirrors.Directions{ + In: strconv.Itoa(mirrorDirectionIN), + Out: strconv.Itoa(mirrorDirectionIN + 1), + }, + } + + mirror, err := tapmirrors.Create(context.TODO(), client, createopts).Extract() + if err != nil { + return nil, err + } + + th.AssertEquals(t, mirror.Name, mirrorName) + th.AssertEquals(t, mirror.Description, mirrorDescription) + + t.Logf("Created Tap Mirror: %s", mirror.ID) + return mirror, nil +} diff --git a/internal/acceptance/openstack/networking/v2/extensions/taas/tapmirrors_test.go b/internal/acceptance/openstack/networking/v2/extensions/taas/tapmirrors_test.go new file mode 100644 index 0000000000..8fe74c0b51 --- /dev/null +++ b/internal/acceptance/openstack/networking/v2/extensions/taas/tapmirrors_test.go @@ -0,0 +1,39 @@ +//go:build acceptance || networking || taas + +package taas + +import ( + "testing" + + "github.com/gophercloud/gophercloud/v2/internal/acceptance/clients" + networking "github.com/gophercloud/gophercloud/v2/internal/acceptance/openstack/networking/v2" + "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" + th "github.com/gophercloud/gophercloud/v2/testhelper" +) + +func TestTapMirrorCRUD(t *testing.T) { + client, err := clients.NewNetworkV2Client() + th.AssertNoErr(t, err) + + // Skip these tests if we don't have the required extension + networking.RequireNeutronExtension(t, client, "taas") + + // Create Port + network, err := networking.CreateNetwork(t, client) + th.AssertNoErr(t, err) + defer networking.DeleteNetwork(t, client, network.ID) + + subnet, err := networking.CreateSubnet(t, client, network.ID) + th.AssertNoErr(t, err) + defer networking.DeleteSubnet(t, client, subnet.ID) + + port, err := networking.CreatePort(t, client, network.ID, subnet.ID) + th.AssertNoErr(t, err) + defer networking.DeletePort(t, client, port.ID) + + // Create Tap Mirror + mirror, err := CreateTapMirror(t, client, port.ID, port.FixedIPs[0].IPAddress) + th.AssertNoErr(t, err) + + tools.PrintResource(t, mirror) +} diff --git a/openstack/networking/v2/extensions/taas/tapmirrors/doc.go b/openstack/networking/v2/extensions/taas/tapmirrors/doc.go new file mode 100644 index 0000000000..481ad3db8e --- /dev/null +++ b/openstack/networking/v2/extensions/taas/tapmirrors/doc.go @@ -0,0 +1,23 @@ +/* +Package tapmirrors manages and retrieves Tap Mirrors in the OpenStack Networking Service. + +Example to Create a Tap Mirror + + createopts := tapmirrors.CreateOpts{ + Name: "tapmirror1", + Description: "Description of tapmirror1", + PortID: "a25290e9-1a54-4c26-a5b3-34458d122acc", + MirrorType: tapmirrors.MirrorTypeErspanv1, + RemoteIP: "192.168.54.217", + Directions: tapmirrors.Directions{ + In: "1", + Out: "2", + }, + } + + mirror, err := tapmirrors.Create(context.TODO(), networkClient, createopts).Extract() + if err != nil { + panic(err) + } +*/ +package tapmirrors diff --git a/openstack/networking/v2/extensions/taas/tapmirrors/requests.go b/openstack/networking/v2/extensions/taas/tapmirrors/requests.go new file mode 100644 index 0000000000..27662fc91e --- /dev/null +++ b/openstack/networking/v2/extensions/taas/tapmirrors/requests.go @@ -0,0 +1,67 @@ +package tapmirrors + +import ( + "context" + + "github.com/gophercloud/gophercloud/v2" +) + +type MirrorType string + +const ( + MirrorTypeErspanv1 MirrorType = "erspanv1" + MirrorTypeGre MirrorType = "gre" +) + +// CreateOptsBuilder allows extensions to add additional parameters to the +// Create request. +type CreateOptsBuilder interface { + ToTapMirrorCreateMap() (map[string]any, error) +} + +// CreateOpts contains all the values needed to create a new tap mirror +type CreateOpts struct { + // The name of the Tap Mirror. + Name string `json:"name"` + + // A human-readable description of the Tap Mirror. + Description string `json:"description,omitempty"` + + // The ID of the project. The caller must have an admin role in + // order to set this. Otherwise, this field is left unset + // and the caller will be the owner. + TenantID string `json:"tenant_id,omitempty"` + + // The Port ID of the Tap Mirror, this will be the source of the mirrored traffic, + // and this traffic will be tunneled into the GRE or ERSPAN v1 tunnel. + // The tunnel itself is not starting from this port. + PortID string `json:"port_id"` + + // The type of the mirroring, it can be gre or erspanv1. + MirrorType MirrorType `json:"mirror_type"` + + // The remote IP of the Tap Mirror, this will be the remote end of the GRE or ERSPAN v1 tunnel. + RemoteIP string `json:"remote_ip"` + + // A dictionary of direction and tunnel_id. Directions are IN and OUT. + // The values of the directions must be unique within the project and + // must be convertible to int. + Directions Directions `json:"directions"` +} + +// ToTapMirrorCreateMap casts a CreateOpts struct to a map. +func (opts CreateOpts) ToTapMirrorCreateMap() (map[string]any, error) { + return gophercloud.BuildRequestBody(opts, "tap_mirror") +} + +// Create accepts a CreateOpts struct and uses the values to create a new Tap Mirror. +func Create(ctx context.Context, c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { + b, err := opts.ToTapMirrorCreateMap() + if err != nil { + r.Err = err + return + } + resp, err := c.Post(ctx, rootURL(c), b, &r.Body, nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} diff --git a/openstack/networking/v2/extensions/taas/tapmirrors/results.go b/openstack/networking/v2/extensions/taas/tapmirrors/results.go new file mode 100644 index 0000000000..51b1164e50 --- /dev/null +++ b/openstack/networking/v2/extensions/taas/tapmirrors/results.go @@ -0,0 +1,69 @@ +package tapmirrors + +import ( + "github.com/gophercloud/gophercloud/v2" +) + +// TapMirror represents a Tap Mirror of the networking service taas extension +type TapMirror struct { + // The ID of the Tap Mirror. + ID string `json:"id"` + + // The name of the Tap Mirror. + Name string `json:"name"` + + // A human-readable description of the Tap Mirror. + Description string `json:"description"` + + // The ID of the tenant. + TenantID string `json:"tenant_id"` + + // The ID of the project. + ProjectID string `json:"project_id"` + + // The Port ID of the Tap Mirror, this will be the source of the mirrored traffic, + // and this traffic will be tunneled into the GRE or ERSPAN v1 tunnel. + // The tunnel itself is not starting from this port. + PortID string `json:"port_id"` + + // The type of the mirroring, it can be gre or erspanv1. + MirrorType string `json:"mirror_type"` + + // The remote IP of the Tap Mirror, this will be the remote end of the GRE or ERSPAN v1 tunnel. + RemoteIP string `json:"remote_ip"` + + // A dictionary of direction and tunnel_id. Directions are In and Out. In specifies + // ingress traffic to the port will be mirrored, Out specifies egress traffic will be mirrored. + // The values of the directions are the identifiers of the ERSPAN or GRE session between + // the source and destination, these must be unique within the project and must be convertible to int. + Directions Directions `json:"directions"` +} + +type Directions struct { + // Unique identifier of the tunnel with ingress traffic. Must be convertible to int. + // Omit to not capture ingress traffic. + In string `json:"IN,omitempty"` + + // Unique identifier of the tunnel with egress traffic. Must be convertible to int. + // Omit to not capture egress traffic. + Out string `json:"OUT,omitempty"` +} + +type commonResult struct { + gophercloud.Result +} + +// Extract is a function that accepts a result and extracts a Tap Mirror. +func (r commonResult) Extract() (*TapMirror, error) { + var s struct { + TapMirror *TapMirror `json:"tap_mirror"` + } + err := r.ExtractInto(&s) + return s.TapMirror, err +} + +// CreateResult represents the result of a create operation. Call its Extract +// method to interpret it as a Tap Mirror. +type CreateResult struct { + commonResult +} diff --git a/openstack/networking/v2/extensions/taas/tapmirrors/testing/requests_test.go b/openstack/networking/v2/extensions/taas/tapmirrors/testing/requests_test.go new file mode 100644 index 0000000000..eac8d40c1e --- /dev/null +++ b/openstack/networking/v2/extensions/taas/tapmirrors/testing/requests_test.go @@ -0,0 +1,91 @@ +package testing + +import ( + "context" + "fmt" + "net/http" + "testing" + + fake "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/common" + "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/taas/tapmirrors" + + th "github.com/gophercloud/gophercloud/v2/testhelper" +) + +func TestCreate(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + fakeServer.Mux.HandleFunc("/v2.0/taas/tap_mirrors", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestJSONRequest(t, r, ` +{ + "tap_mirror": { + "description": "description", + "directions": { + "IN": "1", + "OUT": "2" + }, + "mirror_type": "erspanv1", + "name": "test", + "port_id": "a25290e9-1a54-4c26-a5b3-34458d122acc", + "remote_ip": "192.168.54.217" + } +} + `) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + + fmt.Fprint(w, ` +{ + "tap_mirror": { + "id": "bd64a6e3-12b8-4092-a348-6fc7e27c298a", + "project_id": "6776f022d64443a898ee3fab89dc8c05", + "name": "test", + "description": "description", + "port_id": "a25290e9-1a54-4c26-a5b3-34458d122acc", + "directions": { + "IN": "1", + "OUT": "2" + }, + "remote_ip": "192.168.54.217", + "mirror_type": "erspanv1", + "tenant_id": "6776f022d64443a898ee3fab89dc8c05" + } +} + `) + }) + + options := tapmirrors.CreateOpts{ + Name: "test", + Description: "description", + PortID: "a25290e9-1a54-4c26-a5b3-34458d122acc", + MirrorType: tapmirrors.MirrorTypeErspanv1, + RemoteIP: "192.168.54.217", + Directions: tapmirrors.Directions{ + In: "1", + Out: "2", + }, + } + actual, err := tapmirrors.Create(context.TODO(), fake.ServiceClient(fakeServer), options).Extract() + th.AssertNoErr(t, err) + expected := tapmirrors.TapMirror{ + ID: "bd64a6e3-12b8-4092-a348-6fc7e27c298a", + TenantID: "6776f022d64443a898ee3fab89dc8c05", + ProjectID: "6776f022d64443a898ee3fab89dc8c05", + Name: "test", + Description: "description", + PortID: "a25290e9-1a54-4c26-a5b3-34458d122acc", + MirrorType: "erspanv1", + RemoteIP: "192.168.54.217", + Directions: tapmirrors.Directions{ + In: "1", + Out: "2", + }, + } + th.AssertDeepEquals(t, expected, *actual) +} diff --git a/openstack/networking/v2/extensions/taas/tapmirrors/urls.go b/openstack/networking/v2/extensions/taas/tapmirrors/urls.go new file mode 100644 index 0000000000..fc291c9573 --- /dev/null +++ b/openstack/networking/v2/extensions/taas/tapmirrors/urls.go @@ -0,0 +1,12 @@ +package tapmirrors + +import "github.com/gophercloud/gophercloud/v2" + +const ( + rootPath = "taas" + resourcePath = "tap_mirrors" +) + +func rootURL(c *gophercloud.ServiceClient) string { + return c.ServiceURL(rootPath, resourcePath) +} From bc9ccfa268289e47af4ffeab156a86baef8ebbf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zden=C4=9Bk=20Vydra?= <80331839+vydrazde@users.noreply.github.com> Date: Thu, 7 Aug 2025 13:17:28 +0200 Subject: [PATCH 237/429] Add networking taas tapmirror list, get, update and delete --- .../networking/v2/extensions/taas/taas.go | 18 +- .../v2/extensions/taas/tapmirrors_test.go | 40 +++- .../v2/extensions/taas/tapmirrors/doc.go | 40 ++++ .../v2/extensions/taas/tapmirrors/requests.go | 88 ++++++++ .../v2/extensions/taas/tapmirrors/results.go | 60 ++++++ .../taas/tapmirrors/testing/requests_test.go | 200 ++++++++++++++++++ .../v2/extensions/taas/tapmirrors/urls.go | 4 + 7 files changed, 447 insertions(+), 3 deletions(-) diff --git a/internal/acceptance/openstack/networking/v2/extensions/taas/taas.go b/internal/acceptance/openstack/networking/v2/extensions/taas/taas.go index 026c5d2292..cbab622398 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/taas/taas.go +++ b/internal/acceptance/openstack/networking/v2/extensions/taas/taas.go @@ -36,9 +36,23 @@ func CreateTapMirror(t *testing.T, client *gophercloud.ServiceClient, portID str return nil, err } - th.AssertEquals(t, mirror.Name, mirrorName) - th.AssertEquals(t, mirror.Description, mirrorDescription) + th.AssertEquals(t, mirrorName, mirror.Name) + th.AssertEquals(t, mirrorDescription, mirror.Description) t.Logf("Created Tap Mirror: %s", mirror.ID) return mirror, nil } + +// DeleteTapMirror will delete a Tap Mirror with a specified ID. A fatal error will +// occur if the delete was not successful. This works best when used as a +// deferred function. +func DeleteTapMirror(t *testing.T, client *gophercloud.ServiceClient, mirrorID string) { + t.Logf("Attempting to delete Tap Mirror: %s", mirrorID) + + err := tapmirrors.Delete(context.TODO(), client, mirrorID).ExtractErr() + if err != nil { + t.Fatalf("Unable to delete Tap Mirror %s: %v", mirrorID, err) + } + + t.Logf("Deleted Tap Mirror: %s", mirrorID) +} diff --git a/internal/acceptance/openstack/networking/v2/extensions/taas/tapmirrors_test.go b/internal/acceptance/openstack/networking/v2/extensions/taas/tapmirrors_test.go index 8fe74c0b51..b46d5ae581 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/taas/tapmirrors_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/taas/tapmirrors_test.go @@ -3,14 +3,34 @@ package taas import ( + "context" "testing" "github.com/gophercloud/gophercloud/v2/internal/acceptance/clients" networking "github.com/gophercloud/gophercloud/v2/internal/acceptance/openstack/networking/v2" "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" + "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/taas/tapmirrors" th "github.com/gophercloud/gophercloud/v2/testhelper" ) +func TestTapMirrorList(t *testing.T) { + client, err := clients.NewNetworkV2Client() + th.AssertNoErr(t, err) + + // Skip these tests if we don't have the required extension + networking.RequireNeutronExtension(t, client, "taas") + + allPages, err := tapmirrors.List(client, nil).AllPages(context.TODO()) + th.AssertNoErr(t, err) + + allMirrors, err := tapmirrors.ExtractTapMirrors(allPages) + th.AssertNoErr(t, err) + + for _, mirror := range allMirrors { + tools.PrintResource(t, mirror) + } +} + func TestTapMirrorCRUD(t *testing.T) { client, err := clients.NewNetworkV2Client() th.AssertNoErr(t, err) @@ -31,9 +51,27 @@ func TestTapMirrorCRUD(t *testing.T) { th.AssertNoErr(t, err) defer networking.DeletePort(t, client, port.ID) - // Create Tap Mirror + // Create and defer Delete Tap Mirror mirror, err := CreateTapMirror(t, client, port.ID, port.FixedIPs[0].IPAddress) th.AssertNoErr(t, err) + defer DeleteTapMirror(t, client, mirror.ID) tools.PrintResource(t, mirror) + + // Get Tap Mirror + newmirror, err := tapmirrors.Get(context.TODO(), client, mirror.ID).Extract() + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, mirror, newmirror) + + // Update Tap Mirror + updatedName := "TESTACC-updated name" + updatedDescription := "TESTACC-updated mirror description" + updateOpts := tapmirrors.UpdateOpts{ + Name: &updatedName, + Description: &updatedDescription, + } + updatedmirror, err := tapmirrors.Update(context.TODO(), client, mirror.ID, updateOpts).Extract() + th.AssertNoErr(t, err) + th.AssertEquals(t, updatedName, updatedmirror.Name) + th.AssertEquals(t, updatedDescription, updatedmirror.Description) } diff --git a/openstack/networking/v2/extensions/taas/tapmirrors/doc.go b/openstack/networking/v2/extensions/taas/tapmirrors/doc.go index 481ad3db8e..46e1d9966b 100644 --- a/openstack/networking/v2/extensions/taas/tapmirrors/doc.go +++ b/openstack/networking/v2/extensions/taas/tapmirrors/doc.go @@ -19,5 +19,45 @@ Example to Create a Tap Mirror if err != nil { panic(err) } + +Example to Show the details of a specific Tap Mirror by ID + + tapMirror, err := tapmirrors.Get(context.TODO(), networkClient, "f2b08c1e-aa81-4668-8ae1-1401bcb0576c").Extract() + if err != nil { + panic(err) + } + +Example to Delete a Tap Mirror + + err = tapmirrors.Delete(context.TODO(), networkClient, "5291b189-fd84-46e5-84bd-78f40c05d69c").ExtractErr() + if err != nil { + panic(err) + } + +Example to Update an Tap Mirror + + name := "updated name" + description := "updated description" + updateOps := tapmirrors.UpdateOpts{ + Description: &description, + Name: &name, + } + + updatedTapMirror, err := tapmirrors.Update(context.TODO(), networkClient, "5c561d9d-eaea-45f6-ae3e-08d1a7080828", updateOps).Extract() + if err != nil { + panic(err) + } + +Example to List Tap Mirrors + + allPages, err := tapmirrors.List(networkClient, nil).AllPages(context.TODO()) + if err != nil { + panic(err) + } + + allTapMirrors, err := tapmirrors.ExtractTapMirrors(allPages) + if err != nil { + panic(err) + } */ package tapmirrors diff --git a/openstack/networking/v2/extensions/taas/tapmirrors/requests.go b/openstack/networking/v2/extensions/taas/tapmirrors/requests.go index 27662fc91e..61887314b6 100644 --- a/openstack/networking/v2/extensions/taas/tapmirrors/requests.go +++ b/openstack/networking/v2/extensions/taas/tapmirrors/requests.go @@ -4,6 +4,7 @@ import ( "context" "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/pagination" ) type MirrorType string @@ -65,3 +66,90 @@ func Create(ctx context.Context, c *gophercloud.ServiceClient, opts CreateOptsBu _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return } + +// Get retrieves a particular Tap Mirror on its ID. +func Get(ctx context.Context, c *gophercloud.ServiceClient, id string) (r GetResult) { + resp, err := c.Get(ctx, resourceURL(c, id), &r.Body, nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + +// ListOptsBuilder allows extensions to add additional parameters to the +// List request. +type ListOptsBuilder interface { + ToTapMirrorListQuery() (string, error) +} + +// ListOpts allows the filtering of paginated collections through +// the API. Filtering is achieved by passing in struct field values that map to +// the Endpoint group attributes you want to see returned. +type ListOpts struct { + ProjectID string `q:"project_id"` + Name string `q:"name"` + Description string `q:"description"` + TenantID string `q:"tenant_id"` + PortID string `q:"port_id"` + MirrorType MirrorType `q:"mirror_type"` + RemoteIP string `q:"remote_ip"` +} + +// ToTapMirrorListQuery formats a ListOpts into a query string. +func (opts ListOpts) ToTapMirrorListQuery() (string, error) { + q, err := gophercloud.BuildQueryString(opts) + return q.String(), err +} + +// List returns a Pager which allows you to iterate over a collection of +// Tap Mirrors. It accepts a ListOpts struct, which allows you to filter +// the returned collection for greater efficiency. +func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { + url := rootURL(c) + if opts != nil { + query, err := opts.ToTapMirrorListQuery() + if err != nil { + return pagination.Pager{Err: err} + } + url += query + } + return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page { + return TapMirrorPage{pagination.LinkedPageBase{PageResult: r}} + }) +} + +// Delete will permanently delete a Tap Mirror based on its ID. +func Delete(ctx context.Context, c *gophercloud.ServiceClient, id string) (r DeleteResult) { + resp, err := c.Delete(ctx, resourceURL(c, id), nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + +// UpdateOptsBuilder allows extensions to add additional parameters to the +// Update request. +type UpdateOptsBuilder interface { + ToTapMirrorUpdateMap() (map[string]any, error) +} + +// UpdateOpts contains the values used when updating a Tap Mirror. +type UpdateOpts struct { + Description *string `json:"description,omitempty"` + Name *string `json:"name,omitempty"` +} + +// ToTapMirrorUpdateMap casts an UpdateOpts struct to a map. +func (opts UpdateOpts) ToTapMirrorUpdateMap() (map[string]any, error) { + return gophercloud.BuildRequestBody(opts, "tap_mirror") +} + +// Update allows Tap Mirrors to be updated. +func Update(ctx context.Context, c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) { + b, err := opts.ToTapMirrorUpdateMap() + if err != nil { + r.Err = err + return + } + resp, err := c.Put(ctx, resourceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{ + OkCodes: []int{200}, + }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} diff --git a/openstack/networking/v2/extensions/taas/tapmirrors/results.go b/openstack/networking/v2/extensions/taas/tapmirrors/results.go index 51b1164e50..fa83b876da 100644 --- a/openstack/networking/v2/extensions/taas/tapmirrors/results.go +++ b/openstack/networking/v2/extensions/taas/tapmirrors/results.go @@ -2,6 +2,7 @@ package tapmirrors import ( "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/pagination" ) // TapMirror represents a Tap Mirror of the networking service taas extension @@ -62,8 +63,67 @@ func (r commonResult) Extract() (*TapMirror, error) { return s.TapMirror, err } +// TapMirrorPage is the page returned by a pager when traversing over a +// collection of Policies. +type TapMirrorPage struct { + pagination.LinkedPageBase +} + +// NextPageURL is invoked when a paginated collection of Endpoint groups has +// reached the end of a page and the pager seeks to traverse over a new one. +// In order to do this, it needs to construct the next page's URL. +func (r TapMirrorPage) NextPageURL(endpointURL string) (string, error) { + var s struct { + Links []gophercloud.Link `json:"tap_mirrors_links"` + } + err := r.ExtractInto(&s) + if err != nil { + return "", err + } + return gophercloud.ExtractNextURL(s.Links) +} + +// IsEmpty checks whether an TapMirrorPage struct is empty. +func (r TapMirrorPage) IsEmpty() (bool, error) { + if r.StatusCode == 204 { + return true, nil + } + + is, err := ExtractTapMirrors(r) + return len(is) == 0, err +} + +// ExtractTapMirrors accepts a Page struct, specifically an TapMirrorPage struct, +// and extracts the elements into a slice of Tap Mirror structs. In other words, +// a generic collection is mapped into a relevant slice. +func ExtractTapMirrors(r pagination.Page) ([]TapMirror, error) { + var s struct { + TapMirrors []TapMirror `json:"tap_mirrors"` + } + err := (r.(TapMirrorPage)).ExtractInto(&s) + return s.TapMirrors, err +} + // CreateResult represents the result of a create operation. Call its Extract // method to interpret it as a Tap Mirror. type CreateResult struct { commonResult } + +// GetResult represents the result of a get operation. Call its Extract +// method to interpret it as a TapMirror. +type GetResult struct { + commonResult +} + +// DeleteResult represents the results of a Delete operation. Call its ExtractErr method +// to determine whether the operation succeeded or failed. +type DeleteResult struct { + gophercloud.ErrResult +} + +// UpdateResult represents the result of an update operation. Call its Extract method +// to interpret it as a TapMirror. +type UpdateResult struct { + commonResult +} diff --git a/openstack/networking/v2/extensions/taas/tapmirrors/testing/requests_test.go b/openstack/networking/v2/extensions/taas/tapmirrors/testing/requests_test.go index eac8d40c1e..f9819745ac 100644 --- a/openstack/networking/v2/extensions/taas/tapmirrors/testing/requests_test.go +++ b/openstack/networking/v2/extensions/taas/tapmirrors/testing/requests_test.go @@ -8,6 +8,7 @@ import ( fake "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/common" "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/taas/tapmirrors" + "github.com/gophercloud/gophercloud/v2/pagination" th "github.com/gophercloud/gophercloud/v2/testhelper" ) @@ -89,3 +90,202 @@ func TestCreate(t *testing.T) { } th.AssertDeepEquals(t, expected, *actual) } + +func TestGet(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + fakeServer.Mux.HandleFunc("/v2.0/taas/tap_mirrors/0837b488-f0e2-4689-99b3-e3ed531f9b10", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, ` +{ + "tap_mirror": { + "id": "0837b488-f0e2-4689-99b3-e3ed531f9b10", + "project_id": "6776f022d64443a898ee3fab89dc8c05", + "name": "test", + "description": "description", + "port_id": "a25290e9-1a54-4c26-a5b3-34458d122acc", + "directions": { + "IN": "1", + "OUT": "2" + }, + "remote_ip": "192.168.54.217", + "mirror_type": "erspanv1", + "tenant_id": "6776f022d64443a898ee3fab89dc8c05" + } +} + `) + }) + + actual, err := tapmirrors.Get(context.TODO(), fake.ServiceClient(fakeServer), "0837b488-f0e2-4689-99b3-e3ed531f9b10").Extract() + th.AssertNoErr(t, err) + expected := tapmirrors.TapMirror{ + ID: "0837b488-f0e2-4689-99b3-e3ed531f9b10", + TenantID: "6776f022d64443a898ee3fab89dc8c05", + ProjectID: "6776f022d64443a898ee3fab89dc8c05", + Name: "test", + Description: "description", + PortID: "a25290e9-1a54-4c26-a5b3-34458d122acc", + MirrorType: "erspanv1", + RemoteIP: "192.168.54.217", + Directions: tapmirrors.Directions{ + In: "1", + Out: "2", + }, + } + th.AssertDeepEquals(t, expected, *actual) +} + +func TestDelete(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + fakeServer.Mux.HandleFunc("/v2.0/taas/tap_mirrors/0837b488-f0e2-4689-99b3-e3ed531f9b10", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "DELETE") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + w.WriteHeader(http.StatusNoContent) + }) + + res := tapmirrors.Delete(context.TODO(), fake.ServiceClient(fakeServer), "0837b488-f0e2-4689-99b3-e3ed531f9b10") + th.AssertNoErr(t, res.Err) +} + +func TestList(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + fakeServer.Mux.HandleFunc("/v2.0/taas/tap_mirrors", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, ` +{ + "tap_mirrors": [ + { + "id": "0837b488-f0e2-4689-99b3-e3ed531f9b10", + "project_id": "6776f022d64443a898ee3fab89dc8c05", + "name": "test", + "description": "description", + "port_id": "a25290e9-1a54-4c26-a5b3-34458d122acc", + "directions": { + "IN": "1", + "OUT": "2" + }, + "remote_ip": "192.168.54.217", + "mirror_type": "erspanv1", + "tenant_id": "6776f022d64443a898ee3fab89dc8c05" + } + ] +} + `) + }) + + count := 0 + + err := tapmirrors.List(fake.ServiceClient(fakeServer), tapmirrors.ListOpts{}).EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) { + count++ + actual, err := tapmirrors.ExtractTapMirrors(page) + if err != nil { + t.Errorf("Failed to extract members: %v", err) + return false, err + } + expected := []tapmirrors.TapMirror{ + { + ID: "0837b488-f0e2-4689-99b3-e3ed531f9b10", + TenantID: "6776f022d64443a898ee3fab89dc8c05", + ProjectID: "6776f022d64443a898ee3fab89dc8c05", + Name: "test", + Description: "description", + PortID: "a25290e9-1a54-4c26-a5b3-34458d122acc", + MirrorType: "erspanv1", + RemoteIP: "192.168.54.217", + Directions: tapmirrors.Directions{ + In: "1", + Out: "2", + }, + }, + } + th.CheckDeepEquals(t, expected, actual) + + return true, nil + }) + th.AssertNoErr(t, err) + + if count != 1 { + t.Errorf("Expected 1 page, got %d", count) + } +} + +func TestUpdate(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + fakeServer.Mux.HandleFunc("/v2.0/taas/tap_mirrors/d031da31-fb9b-4bd9-8d37-aaf04a12d45f", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "PUT") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestJSONRequest(t, r, ` +{ + "tap_mirror": { + "name": "new name", + "description": "new description" + } +} + `) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, ` +{ + "tap_mirror": { + "id": "d031da31-fb9b-4bd9-8d37-aaf04a12d45f", + "project_id": "6776f022d64443a898ee3fab89dc8c05", + "name": "new name", + "description": "new description", + "port_id": "a25290e9-1a54-4c26-a5b3-34458d122acc", + "directions": { + "IN": "1", + "OUT": "2" + }, + "remote_ip": "192.168.54.217", + "mirror_type": "erspanv1", + "tenant_id": "6776f022d64443a898ee3fab89dc8c05" + } +} +`) + }) + + updatedName := "new name" + updatedDescription := "new description" + options := tapmirrors.UpdateOpts{ + Name: &updatedName, + Description: &updatedDescription, + } + + actual, err := tapmirrors.Update(context.TODO(), fake.ServiceClient(fakeServer), "d031da31-fb9b-4bd9-8d37-aaf04a12d45f", options).Extract() + th.AssertNoErr(t, err) + expected := tapmirrors.TapMirror{ + ID: "d031da31-fb9b-4bd9-8d37-aaf04a12d45f", + TenantID: "6776f022d64443a898ee3fab89dc8c05", + ProjectID: "6776f022d64443a898ee3fab89dc8c05", + Name: "new name", + Description: "new description", + PortID: "a25290e9-1a54-4c26-a5b3-34458d122acc", + MirrorType: "erspanv1", + RemoteIP: "192.168.54.217", + Directions: tapmirrors.Directions{ + In: "1", + Out: "2", + }, + } + th.AssertDeepEquals(t, expected, *actual) +} diff --git a/openstack/networking/v2/extensions/taas/tapmirrors/urls.go b/openstack/networking/v2/extensions/taas/tapmirrors/urls.go index fc291c9573..1b38a7cec3 100644 --- a/openstack/networking/v2/extensions/taas/tapmirrors/urls.go +++ b/openstack/networking/v2/extensions/taas/tapmirrors/urls.go @@ -10,3 +10,7 @@ const ( func rootURL(c *gophercloud.ServiceClient) string { return c.ServiceURL(rootPath, resourcePath) } + +func resourceURL(c *gophercloud.ServiceClient, id string) string { + return c.ServiceURL(rootPath, resourcePath, id) +} From 1fd250626bda8339009fe486ed1366ec1c4067e8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Aug 2025 09:19:37 +0000 Subject: [PATCH 238/429] build(deps): bump golang.org/x/crypto from 0.40.0 to 0.41.0 Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.40.0 to 0.41.0. - [Commits](https://github.com/golang/crypto/compare/v0.40.0...v0.41.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-version: 0.41.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 210e9ada68..9b62787571 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,8 @@ go 1.23.0 toolchain go1.23.6 require ( - golang.org/x/crypto v0.40.0 + golang.org/x/crypto v0.41.0 gopkg.in/yaml.v2 v2.4.0 ) -require golang.org/x/sys v0.34.0 // indirect +require golang.org/x/sys v0.35.0 // indirect diff --git a/go.sum b/go.sum index 6c13d941f0..f1687a61ee 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ -golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= -golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= -golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= -golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= -golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= +golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= +golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= +golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= From 2c6c60b38f2863b9818c12f95e1d6afd79cea96b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zden=C4=9Bk=20Vydra?= <80331839+vydrazde@users.noreply.github.com> Date: Fri, 8 Aug 2025 14:00:14 +0200 Subject: [PATCH 239/429] Change Direction value type to int --- .../networking/v2/extensions/taas/taas.go | 5 ++--- .../v2/extensions/taas/tapmirrors/requests.go | 7 ++++--- .../v2/extensions/taas/tapmirrors/results.go | 14 ++++++------- .../taas/tapmirrors/testing/requests_test.go | 20 +++++++++---------- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/internal/acceptance/openstack/networking/v2/extensions/taas/taas.go b/internal/acceptance/openstack/networking/v2/extensions/taas/taas.go index cbab622398..3d4f3979f4 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/taas/taas.go +++ b/internal/acceptance/openstack/networking/v2/extensions/taas/taas.go @@ -2,7 +2,6 @@ package taas import ( "context" - "strconv" "testing" "github.com/gophercloud/gophercloud/v2" @@ -26,8 +25,8 @@ func CreateTapMirror(t *testing.T, client *gophercloud.ServiceClient, portID str MirrorType: tapmirrors.MirrorTypeErspanv1, RemoteIP: remoteIP, Directions: tapmirrors.Directions{ - In: strconv.Itoa(mirrorDirectionIN), - Out: strconv.Itoa(mirrorDirectionIN + 1), + In: mirrorDirectionIN, + Out: mirrorDirectionIN + 1, }, } diff --git a/openstack/networking/v2/extensions/taas/tapmirrors/requests.go b/openstack/networking/v2/extensions/taas/tapmirrors/requests.go index 61887314b6..7b236374bd 100644 --- a/openstack/networking/v2/extensions/taas/tapmirrors/requests.go +++ b/openstack/networking/v2/extensions/taas/tapmirrors/requests.go @@ -44,9 +44,10 @@ type CreateOpts struct { // The remote IP of the Tap Mirror, this will be the remote end of the GRE or ERSPAN v1 tunnel. RemoteIP string `json:"remote_ip"` - // A dictionary of direction and tunnel_id. Directions are IN and OUT. - // The values of the directions must be unique within the project and - // must be convertible to int. + // A dictionary of direction and tunnel_id. Directions are In and Out. In specifies + // ingress traffic to the port will be mirrored, Out specifies egress traffic will be mirrored. + // The values of the directions are the identifiers of the ERSPAN or GRE session between + // the source and destination, these must be unique within the project. Directions Directions `json:"directions"` } diff --git a/openstack/networking/v2/extensions/taas/tapmirrors/results.go b/openstack/networking/v2/extensions/taas/tapmirrors/results.go index fa83b876da..f6ca8b1aa0 100644 --- a/openstack/networking/v2/extensions/taas/tapmirrors/results.go +++ b/openstack/networking/v2/extensions/taas/tapmirrors/results.go @@ -36,18 +36,18 @@ type TapMirror struct { // A dictionary of direction and tunnel_id. Directions are In and Out. In specifies // ingress traffic to the port will be mirrored, Out specifies egress traffic will be mirrored. // The values of the directions are the identifiers of the ERSPAN or GRE session between - // the source and destination, these must be unique within the project and must be convertible to int. + // the source and destination, these must be unique within the project. Directions Directions `json:"directions"` } type Directions struct { - // Unique identifier of the tunnel with ingress traffic. Must be convertible to int. - // Omit to not capture ingress traffic. - In string `json:"IN,omitempty"` + // Unique identifier of the tunnel with ingress traffic. Omit to not capture ingress traffic. + // Encoded as JSON string to be compatible with python tap-as-a-service client. + In int `json:"IN,omitempty,string"` - // Unique identifier of the tunnel with egress traffic. Must be convertible to int. - // Omit to not capture egress traffic. - Out string `json:"OUT,omitempty"` + // Unique identifier of the tunnel with egress traffic. Omit to not capture egress traffic. + // Encoded as JSON string to be compatible with python tap-as-a-service client. + Out int `json:"OUT,omitempty,string"` } type commonResult struct { diff --git a/openstack/networking/v2/extensions/taas/tapmirrors/testing/requests_test.go b/openstack/networking/v2/extensions/taas/tapmirrors/testing/requests_test.go index f9819745ac..7d98c403b5 100644 --- a/openstack/networking/v2/extensions/taas/tapmirrors/testing/requests_test.go +++ b/openstack/networking/v2/extensions/taas/tapmirrors/testing/requests_test.go @@ -68,8 +68,8 @@ func TestCreate(t *testing.T) { MirrorType: tapmirrors.MirrorTypeErspanv1, RemoteIP: "192.168.54.217", Directions: tapmirrors.Directions{ - In: "1", - Out: "2", + In: 1, + Out: 2, }, } actual, err := tapmirrors.Create(context.TODO(), fake.ServiceClient(fakeServer), options).Extract() @@ -84,8 +84,8 @@ func TestCreate(t *testing.T) { MirrorType: "erspanv1", RemoteIP: "192.168.54.217", Directions: tapmirrors.Directions{ - In: "1", - Out: "2", + In: 1, + Out: 2, }, } th.AssertDeepEquals(t, expected, *actual) @@ -134,8 +134,8 @@ func TestGet(t *testing.T) { MirrorType: "erspanv1", RemoteIP: "192.168.54.217", Directions: tapmirrors.Directions{ - In: "1", - Out: "2", + In: 1, + Out: 2, }, } th.AssertDeepEquals(t, expected, *actual) @@ -207,8 +207,8 @@ func TestList(t *testing.T) { MirrorType: "erspanv1", RemoteIP: "192.168.54.217", Directions: tapmirrors.Directions{ - In: "1", - Out: "2", + In: 1, + Out: 2, }, }, } @@ -283,8 +283,8 @@ func TestUpdate(t *testing.T) { MirrorType: "erspanv1", RemoteIP: "192.168.54.217", Directions: tapmirrors.Directions{ - In: "1", - Out: "2", + In: 1, + Out: 2, }, } th.AssertDeepEquals(t, expected, *actual) From 9bfae3eb292bad158a5d623112b9b7ecedc8d8d2 Mon Sep 17 00:00:00 2001 From: "peter.bro" Date: Wed, 26 Mar 2025 15:28:27 +0900 Subject: [PATCH 240/429] [Key-Manager] resolve ContainerConsumerListOpts receiver error issue --- openstack/keymanager/v1/containers/requests.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openstack/keymanager/v1/containers/requests.go b/openstack/keymanager/v1/containers/requests.go index a611ef91e0..5797153b14 100644 --- a/openstack/keymanager/v1/containers/requests.go +++ b/openstack/keymanager/v1/containers/requests.go @@ -123,7 +123,7 @@ type ListConsumersOpts struct { // ToContainerListConsumersQuery formats a ListConsumersOpts into a query // string. -func (opts ListOpts) ToContainerListConsumersQuery() (string, error) { +func (opts ListConsumersOpts) ToContainerListConsumersQuery() (string, error) { q, err := gophercloud.BuildQueryString(opts) return q.String(), err } From eecd1a9603098928c1b1e7fa22a1c4ee08a7f172 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Aug 2025 18:04:35 +0000 Subject: [PATCH 241/429] build(deps): bump actions/checkout from 4 to 5 Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql-analysis.yaml | 2 +- .github/workflows/ensure-labels.yaml | 2 +- .github/workflows/functional-baremetal.yaml | 2 +- .github/workflows/functional-basic.yaml | 2 +- .github/workflows/functional-blockstorage.yaml | 2 +- .github/workflows/functional-compute.yaml | 2 +- .github/workflows/functional-containerinfra.yaml | 2 +- .github/workflows/functional-dns.yaml | 2 +- .github/workflows/functional-fwaas_v2.yaml | 2 +- .github/workflows/functional-identity.yaml | 2 +- .github/workflows/functional-image.yaml | 2 +- .github/workflows/functional-keymanager.yaml | 2 +- .github/workflows/functional-loadbalancer.yaml | 2 +- .github/workflows/functional-messaging.yaml | 2 +- .github/workflows/functional-networking.yaml | 2 +- .github/workflows/functional-objectstorage.yaml | 2 +- .github/workflows/functional-orchestration.yaml | 2 +- .github/workflows/functional-placement.yaml | 2 +- .github/workflows/functional-sharedfilesystems.yaml | 2 +- .github/workflows/functional-workflow.yaml | 2 +- .github/workflows/label-pr.yaml | 2 +- .github/workflows/lint.yaml | 2 +- .github/workflows/unit.yaml | 2 +- 23 files changed, 23 insertions(+), 23 deletions(-) diff --git a/.github/workflows/codeql-analysis.yaml b/.github/workflows/codeql-analysis.yaml index 8efeaf761c..58952951c6 100644 --- a/.github/workflows/codeql-analysis.yaml +++ b/.github/workflows/codeql-analysis.yaml @@ -18,7 +18,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup Go uses: actions/setup-go@v5 diff --git a/.github/workflows/ensure-labels.yaml b/.github/workflows/ensure-labels.yaml index 3096aa0104..3f8bd42cb2 100644 --- a/.github/workflows/ensure-labels.yaml +++ b/.github/workflows/ensure-labels.yaml @@ -10,7 +10,7 @@ jobs: ensure: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: micnncim/action-label-syncer@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/functional-baremetal.yaml b/.github/workflows/functional-baremetal.yaml index 8d562f0514..ae0e40333f 100644 --- a/.github/workflows/functional-baremetal.yaml +++ b/.github/workflows/functional-baremetal.yaml @@ -39,7 +39,7 @@ jobs: name: Ironic on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Work around broken dnsmasq run: sudo apt-get purge -y dnsmasq-base - name: Deploy devstack diff --git a/.github/workflows/functional-basic.yaml b/.github/workflows/functional-basic.yaml index 562946a0da..5b28d3c9b1 100644 --- a/.github/workflows/functional-basic.yaml +++ b/.github/workflows/functional-basic.yaml @@ -34,7 +34,7 @@ jobs: name: basic tests on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Deploy devstack uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: diff --git a/.github/workflows/functional-blockstorage.yaml b/.github/workflows/functional-blockstorage.yaml index 2d2f33b981..c747d5b899 100644 --- a/.github/workflows/functional-blockstorage.yaml +++ b/.github/workflows/functional-blockstorage.yaml @@ -39,7 +39,7 @@ jobs: name: Cinder on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Deploy devstack uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: diff --git a/.github/workflows/functional-compute.yaml b/.github/workflows/functional-compute.yaml index c347d93e74..516be94de5 100644 --- a/.github/workflows/functional-compute.yaml +++ b/.github/workflows/functional-compute.yaml @@ -39,7 +39,7 @@ jobs: name: Nova on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Deploy devstack uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: diff --git a/.github/workflows/functional-containerinfra.yaml b/.github/workflows/functional-containerinfra.yaml index 1239962b0c..60df8d7839 100644 --- a/.github/workflows/functional-containerinfra.yaml +++ b/.github/workflows/functional-containerinfra.yaml @@ -63,7 +63,7 @@ jobs: name: Magnum on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Deploy devstack uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: diff --git a/.github/workflows/functional-dns.yaml b/.github/workflows/functional-dns.yaml index 042ab75fca..243cd71e8b 100644 --- a/.github/workflows/functional-dns.yaml +++ b/.github/workflows/functional-dns.yaml @@ -45,7 +45,7 @@ jobs: name: Designate on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Deploy devstack uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: diff --git a/.github/workflows/functional-fwaas_v2.yaml b/.github/workflows/functional-fwaas_v2.yaml index bda886c68b..da944898ae 100644 --- a/.github/workflows/functional-fwaas_v2.yaml +++ b/.github/workflows/functional-fwaas_v2.yaml @@ -43,7 +43,7 @@ jobs: name: FWaaS_v2 on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Create additional neutron policies run: | mkdir /tmp/neutron-policies diff --git a/.github/workflows/functional-identity.yaml b/.github/workflows/functional-identity.yaml index 0db81b6f85..48e605b6f5 100644 --- a/.github/workflows/functional-identity.yaml +++ b/.github/workflows/functional-identity.yaml @@ -39,7 +39,7 @@ jobs: name: Keystone on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Deploy devstack uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: diff --git a/.github/workflows/functional-image.yaml b/.github/workflows/functional-image.yaml index 6e6e884739..5de98b2d95 100644 --- a/.github/workflows/functional-image.yaml +++ b/.github/workflows/functional-image.yaml @@ -39,7 +39,7 @@ jobs: name: Glance on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Deploy devstack uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: diff --git a/.github/workflows/functional-keymanager.yaml b/.github/workflows/functional-keymanager.yaml index 04016bba41..1c3a9a0256 100644 --- a/.github/workflows/functional-keymanager.yaml +++ b/.github/workflows/functional-keymanager.yaml @@ -51,7 +51,7 @@ jobs: name: Barbican on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Deploy devstack uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: diff --git a/.github/workflows/functional-loadbalancer.yaml b/.github/workflows/functional-loadbalancer.yaml index ff35ede770..ad0071c84b 100644 --- a/.github/workflows/functional-loadbalancer.yaml +++ b/.github/workflows/functional-loadbalancer.yaml @@ -45,7 +45,7 @@ jobs: name: Octavia on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Deploy devstack uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: diff --git a/.github/workflows/functional-messaging.yaml b/.github/workflows/functional-messaging.yaml index ee54f43050..aad3ed9754 100644 --- a/.github/workflows/functional-messaging.yaml +++ b/.github/workflows/functional-messaging.yaml @@ -39,7 +39,7 @@ jobs: name: Zaqar on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Deploy devstack uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: diff --git a/.github/workflows/functional-networking.yaml b/.github/workflows/functional-networking.yaml index d07bcce7f5..c1a0661d92 100644 --- a/.github/workflows/functional-networking.yaml +++ b/.github/workflows/functional-networking.yaml @@ -39,7 +39,7 @@ jobs: name: Neutron on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Create additional neutron policies run: | mkdir /tmp/neutron-policies diff --git a/.github/workflows/functional-objectstorage.yaml b/.github/workflows/functional-objectstorage.yaml index 3797c2cdcb..494e44fa1c 100644 --- a/.github/workflows/functional-objectstorage.yaml +++ b/.github/workflows/functional-objectstorage.yaml @@ -39,7 +39,7 @@ jobs: name: Swift on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Deploy devstack uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: diff --git a/.github/workflows/functional-orchestration.yaml b/.github/workflows/functional-orchestration.yaml index 930e31ba63..f54f9d7a81 100644 --- a/.github/workflows/functional-orchestration.yaml +++ b/.github/workflows/functional-orchestration.yaml @@ -39,7 +39,7 @@ jobs: name: Heat on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Deploy devstack uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: diff --git a/.github/workflows/functional-placement.yaml b/.github/workflows/functional-placement.yaml index 43dd35ea72..bacc97940d 100644 --- a/.github/workflows/functional-placement.yaml +++ b/.github/workflows/functional-placement.yaml @@ -39,7 +39,7 @@ jobs: name: Placement on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Deploy devstack uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: diff --git a/.github/workflows/functional-sharedfilesystems.yaml b/.github/workflows/functional-sharedfilesystems.yaml index 8fbc3e3d2b..db803850de 100644 --- a/.github/workflows/functional-sharedfilesystems.yaml +++ b/.github/workflows/functional-sharedfilesystems.yaml @@ -45,7 +45,7 @@ jobs: name: Manila on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Deploy devstack uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: diff --git a/.github/workflows/functional-workflow.yaml b/.github/workflows/functional-workflow.yaml index 5fad4cec42..c0ef7839cd 100644 --- a/.github/workflows/functional-workflow.yaml +++ b/.github/workflows/functional-workflow.yaml @@ -43,7 +43,7 @@ jobs: name: Mistral on Deploy OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Deploy devstack uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: diff --git a/.github/workflows/label-pr.yaml b/.github/workflows/label-pr.yaml index a9a34072f6..15abc3203c 100644 --- a/.github/workflows/label-pr.yaml +++ b/.github/workflows/label-pr.yaml @@ -10,7 +10,7 @@ jobs: semver: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: fetch-depth: 0 ref: ${{ github.event.pull_request.head.sha }} diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index be44ea86bc..4a627ec507 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Gophercloud - uses: actions/checkout@v4 + uses: actions/checkout@v5 - uses: actions/setup-go@v5 with: go-version: '1' diff --git a/.github/workflows/unit.yaml b/.github/workflows/unit.yaml index ae3b2f0059..c462a6dd27 100644 --- a/.github/workflows/unit.yaml +++ b/.github/workflows/unit.yaml @@ -14,7 +14,7 @@ jobs: fail-fast: false steps: - name: Checkout Gophercloud - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup Go uses: actions/setup-go@v5 with: From e852df2d71bed2ac4b55b408ffb087e5238b716d Mon Sep 17 00:00:00 2001 From: Thomas Morin Date: Wed, 13 Aug 2025 15:06:13 +0200 Subject: [PATCH 242/429] Networking v2: Support two time formats for subnet, router, SG rules (#3492) --- .../v2/extensions/layer3/routers/results.go | 42 +++++++++++++++++- .../layer3/routers/testing/requests_test.go | 8 ++++ .../v2/extensions/security/rules/results.go | 43 ++++++++++++++++++- .../security/rules/testing/requests_test.go | 13 ++++++ openstack/networking/v2/subnets/results.go | 43 ++++++++++++++++++- .../v2/subnets/testing/fixtures_test.go | 10 +++++ 6 files changed, 153 insertions(+), 6 deletions(-) diff --git a/openstack/networking/v2/extensions/layer3/routers/results.go b/openstack/networking/v2/extensions/layer3/routers/results.go index e9cd9783bd..73f3b93134 100644 --- a/openstack/networking/v2/extensions/layer3/routers/results.go +++ b/openstack/networking/v2/extensions/layer3/routers/results.go @@ -82,10 +82,48 @@ type Router struct { RevisionNumber int `json:"revision_number"` // Timestamp when the router was created - CreatedAt time.Time `json:"created_at"` + CreatedAt time.Time `json:"-"` // Timestamp when the router was last updated - UpdatedAt time.Time `json:"updated_at"` + UpdatedAt time.Time `json:"-"` +} + +func (r *Router) UnmarshalJSON(b []byte) error { + type tmp Router + + // Support for older neutron time format + var s1 struct { + tmp + CreatedAt gophercloud.JSONRFC3339NoZ `json:"created_at"` + UpdatedAt gophercloud.JSONRFC3339NoZ `json:"updated_at"` + } + + err := json.Unmarshal(b, &s1) + if err == nil { + *r = Router(s1.tmp) + r.CreatedAt = time.Time(s1.CreatedAt) + r.UpdatedAt = time.Time(s1.UpdatedAt) + + return nil + } + + // Support for newer neutron time format + var s2 struct { + tmp + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + } + + err = json.Unmarshal(b, &s2) + if err != nil { + return err + } + + *r = Router(s2.tmp) + r.CreatedAt = time.Time(s2.CreatedAt) + r.UpdatedAt = time.Time(s2.UpdatedAt) + + return nil } // RouterPage is the page returned by a pager when traversing over a diff --git a/openstack/networking/v2/extensions/layer3/routers/testing/requests_test.go b/openstack/networking/v2/extensions/layer3/routers/testing/requests_test.go index f66dda4e06..f6cd2c0bbd 100644 --- a/openstack/networking/v2/extensions/layer3/routers/testing/requests_test.go +++ b/openstack/networking/v2/extensions/layer3/routers/testing/requests_test.go @@ -34,6 +34,8 @@ func TestList(t *testing.T) { "admin_state_up": true, "tenant_id": "6b96ff0cb17a4b859e1e575d221683d3", "distributed": false, + "created_at": "2017-12-28T07:21:40Z", + "updated_at": "2017-12-28T07:21:40Z", "id": "7177abc4-5ae9-4bb7-b0d4-89e94a4abf3b" }, { @@ -45,6 +47,8 @@ func TestList(t *testing.T) { "admin_state_up": true, "tenant_id": "33a40233088643acb66ff6eb0ebea679", "distributed": false, + "created_at": "2017-12-28T07:21:40", + "updated_at": "2017-12-28T07:21:40", "id": "a9254bdb-2613-4a13-ac4c-adc581fba50d" }, { @@ -86,6 +90,8 @@ func TestList(t *testing.T) { Distributed: false, Name: "second_routers", ID: "7177abc4-5ae9-4bb7-b0d4-89e94a4abf3b", + CreatedAt: time.Date(2017, 12, 28, 07, 21, 40, 0, time.UTC), + UpdatedAt: time.Date(2017, 12, 28, 07, 21, 40, 0, time.UTC), TenantID: "6b96ff0cb17a4b859e1e575d221683d3", }, { @@ -95,6 +101,8 @@ func TestList(t *testing.T) { Distributed: false, Name: "router1", ID: "a9254bdb-2613-4a13-ac4c-adc581fba50d", + CreatedAt: time.Date(2017, 12, 28, 07, 21, 40, 0, time.UTC), + UpdatedAt: time.Date(2017, 12, 28, 07, 21, 40, 0, time.UTC), TenantID: "33a40233088643acb66ff6eb0ebea679", }, { diff --git a/openstack/networking/v2/extensions/security/rules/results.go b/openstack/networking/v2/extensions/security/rules/results.go index 9f1a92e355..ddc7c5b7c7 100644 --- a/openstack/networking/v2/extensions/security/rules/results.go +++ b/openstack/networking/v2/extensions/security/rules/results.go @@ -1,6 +1,7 @@ package rules import ( + "encoding/json" "time" "github.com/gophercloud/gophercloud/v2" @@ -67,10 +68,48 @@ type SecGroupRule struct { RevisionNumber int `json:"revision_number"` // Timestamp when the rule was created - CreatedAt time.Time `json:"created_at"` + CreatedAt time.Time `json:"-"` // Timestamp when the rule was last updated - UpdatedAt time.Time `json:"updated_at"` + UpdatedAt time.Time `json:"-"` +} + +func (r *SecGroupRule) UnmarshalJSON(b []byte) error { + type tmp SecGroupRule + + // Support for older neutron time format + var s1 struct { + tmp + CreatedAt gophercloud.JSONRFC3339NoZ `json:"created_at"` + UpdatedAt gophercloud.JSONRFC3339NoZ `json:"updated_at"` + } + + err := json.Unmarshal(b, &s1) + if err == nil { + *r = SecGroupRule(s1.tmp) + r.CreatedAt = time.Time(s1.CreatedAt) + r.UpdatedAt = time.Time(s1.UpdatedAt) + + return nil + } + + // Support for newer neutron time format + var s2 struct { + tmp + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + } + + err = json.Unmarshal(b, &s2) + if err != nil { + return err + } + + *r = SecGroupRule(s2.tmp) + r.CreatedAt = time.Time(s2.CreatedAt) + r.UpdatedAt = time.Time(s2.UpdatedAt) + + return nil } // SecGroupRulePage is the page returned by a pager when traversing over a diff --git a/openstack/networking/v2/extensions/security/rules/testing/requests_test.go b/openstack/networking/v2/extensions/security/rules/testing/requests_test.go index 15975ed4ea..4e1938984b 100644 --- a/openstack/networking/v2/extensions/security/rules/testing/requests_test.go +++ b/openstack/networking/v2/extensions/security/rules/testing/requests_test.go @@ -5,6 +5,7 @@ import ( "fmt" "net/http" "testing" + "time" fake "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/common" "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/security/rules" @@ -35,6 +36,8 @@ func TestList(t *testing.T) { "protocol": null, "remote_group_id": null, "remote_ip_prefix": null, + "created_at": "2017-12-28T07:21:40Z", + "updated_at": "2017-12-28T07:21:40Z", "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" }, @@ -47,6 +50,8 @@ func TestList(t *testing.T) { "protocol": null, "remote_group_id": null, "remote_ip_prefix": null, + "created_at": "2017-12-28T07:21:40", + "updated_at": "2017-12-28T07:21:40", "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" } @@ -76,6 +81,8 @@ func TestList(t *testing.T) { Protocol: "", RemoteGroupID: "", RemoteIPPrefix: "", + CreatedAt: time.Date(2017, 12, 28, 07, 21, 40, 0, time.UTC), + UpdatedAt: time.Date(2017, 12, 28, 07, 21, 40, 0, time.UTC), SecGroupID: "85cc3048-abc3-43cc-89b3-377341426ac5", TenantID: "e4f50856753b4dc6afee5fa6b9b6c550", }, @@ -88,6 +95,8 @@ func TestList(t *testing.T) { Protocol: "", RemoteGroupID: "", RemoteIPPrefix: "", + CreatedAt: time.Date(2017, 12, 28, 07, 21, 40, 0, time.UTC), + UpdatedAt: time.Date(2017, 12, 28, 07, 21, 40, 0, time.UTC), SecGroupID: "85cc3048-abc3-43cc-89b3-377341426ac5", TenantID: "e4f50856753b4dc6afee5fa6b9b6c550", }, @@ -372,6 +381,8 @@ func TestGet(t *testing.T) { "protocol": null, "remote_group_id": null, "remote_ip_prefix": null, + "created_at": "2017-12-28T07:21:40Z", + "updated_at": "2017-12-28T07:21:40Z", "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" } @@ -390,6 +401,8 @@ func TestGet(t *testing.T) { th.AssertEquals(t, "", sr.Protocol) th.AssertEquals(t, "", sr.RemoteGroupID) th.AssertEquals(t, "", sr.RemoteIPPrefix) + th.AssertEquals(t, time.Date(2017, 12, 28, 07, 21, 40, 0, time.UTC), sr.UpdatedAt) + th.AssertEquals(t, time.Date(2017, 12, 28, 07, 21, 40, 0, time.UTC), sr.CreatedAt) th.AssertEquals(t, "85cc3048-abc3-43cc-89b3-377341426ac5", sr.SecGroupID) th.AssertEquals(t, "e4f50856753b4dc6afee5fa6b9b6c550", sr.TenantID) } diff --git a/openstack/networking/v2/subnets/results.go b/openstack/networking/v2/subnets/results.go index bde6823ea7..cb5831e9e6 100644 --- a/openstack/networking/v2/subnets/results.go +++ b/openstack/networking/v2/subnets/results.go @@ -1,6 +1,7 @@ package subnets import ( + "encoding/json" "time" "github.com/gophercloud/gophercloud/v2" @@ -129,10 +130,48 @@ type Subnet struct { SegmentID string `json:"segment_id"` // Timestamp when the subnet was created - CreatedAt time.Time `json:"created_at"` + CreatedAt time.Time `json:"-"` // Timestamp when the subnet was last updated - UpdatedAt time.Time `json:"updated_at"` + UpdatedAt time.Time `json:"-"` +} + +func (r *Subnet) UnmarshalJSON(b []byte) error { + type tmp Subnet + + // Support for older neutron time format + var s1 struct { + tmp + CreatedAt gophercloud.JSONRFC3339NoZ `json:"created_at"` + UpdatedAt gophercloud.JSONRFC3339NoZ `json:"updated_at"` + } + + err := json.Unmarshal(b, &s1) + if err == nil { + *r = Subnet(s1.tmp) + r.CreatedAt = time.Time(s1.CreatedAt) + r.UpdatedAt = time.Time(s1.UpdatedAt) + + return nil + } + + // Support for newer neutron time format + var s2 struct { + tmp + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + } + + err = json.Unmarshal(b, &s2) + if err != nil { + return err + } + + *r = Subnet(s2.tmp) + r.CreatedAt = time.Time(s2.CreatedAt) + r.UpdatedAt = time.Time(s2.UpdatedAt) + + return nil } // SubnetPage is the page returned by a pager when traversing over a collection diff --git a/openstack/networking/v2/subnets/testing/fixtures_test.go b/openstack/networking/v2/subnets/testing/fixtures_test.go index a44f1cc77e..ebb005f62d 100644 --- a/openstack/networking/v2/subnets/testing/fixtures_test.go +++ b/openstack/networking/v2/subnets/testing/fixtures_test.go @@ -1,6 +1,8 @@ package testing import ( + "time" + "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/subnets" ) @@ -24,6 +26,8 @@ const SubnetListResult = ` "ip_version": 4, "gateway_ip": "10.0.0.1", "cidr": "10.0.0.0/24", + "created_at": "2017-12-28T07:21:40Z", + "updated_at": "2017-12-28T07:21:40Z", "id": "08eae331-0402-425a-923c-34f7cfe39c1b" }, { @@ -43,6 +47,8 @@ const SubnetListResult = ` "ip_version": 4, "gateway_ip": "192.0.0.1", "cidr": "192.0.0.0/8", + "created_at": "2017-12-28T07:21:40", + "updated_at": "2017-12-28T07:21:40", "id": "54d6f61d-db07-451c-9ab3-b9609b6b6f0b" }, { @@ -104,6 +110,8 @@ var Subnet1 = subnets.Subnet{ IPVersion: 4, GatewayIP: "10.0.0.1", CIDR: "10.0.0.0/24", + CreatedAt: time.Date(2017, 12, 28, 07, 21, 40, 0, time.UTC), + UpdatedAt: time.Date(2017, 12, 28, 07, 21, 40, 0, time.UTC), ID: "08eae331-0402-425a-923c-34f7cfe39c1b", } @@ -125,6 +133,8 @@ var Subnet2 = subnets.Subnet{ IPVersion: 4, GatewayIP: "192.0.0.1", CIDR: "192.0.0.0/8", + CreatedAt: time.Date(2017, 12, 28, 07, 21, 40, 0, time.UTC), + UpdatedAt: time.Date(2017, 12, 28, 07, 21, 40, 0, time.UTC), ID: "54d6f61d-db07-451c-9ab3-b9609b6b6f0b", } From c249fbc12ca323705abb92892eeca541dd837a10 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 19 Jun 2025 17:53:58 +0100 Subject: [PATCH 243/429] Prepare for merge queues Add merge_group as an event. https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-a-merge-queue Signed-off-by: Stephen Finucane --- .github/workflows/functional-baremetal.yaml | 1 + .github/workflows/functional-basic.yaml | 1 + .github/workflows/functional-blockstorage.yaml | 1 + .github/workflows/functional-compute.yaml | 1 + .github/workflows/functional-containerinfra.yaml | 1 + .github/workflows/functional-dns.yaml | 1 + .github/workflows/functional-fwaas_v2.yaml | 1 + .github/workflows/functional-identity.yaml | 1 + .github/workflows/functional-image.yaml | 1 + .github/workflows/functional-keymanager.yaml | 1 + .github/workflows/functional-loadbalancer.yaml | 1 + .github/workflows/functional-messaging.yaml | 1 + .github/workflows/functional-networking.yaml | 1 + .github/workflows/functional-objectstorage.yaml | 1 + .github/workflows/functional-orchestration.yaml | 1 + .github/workflows/functional-placement.yaml | 1 + .github/workflows/functional-sharedfilesystems.yaml | 1 + .github/workflows/functional-workflow.yaml | 1 + .github/workflows/lint.yaml | 1 + .github/workflows/unit.yaml | 1 + 20 files changed, 20 insertions(+) diff --git a/.github/workflows/functional-baremetal.yaml b/.github/workflows/functional-baremetal.yaml index ae0e40333f..de497cfd3c 100644 --- a/.github/workflows/functional-baremetal.yaml +++ b/.github/workflows/functional-baremetal.yaml @@ -1,5 +1,6 @@ name: functional-baremetal on: + merge_group: pull_request: paths: - 'openstack/auth_env.go' diff --git a/.github/workflows/functional-basic.yaml b/.github/workflows/functional-basic.yaml index 5b28d3c9b1..3e87b70194 100644 --- a/.github/workflows/functional-basic.yaml +++ b/.github/workflows/functional-basic.yaml @@ -1,5 +1,6 @@ name: functional-basic on: + merge_group: pull_request: paths-ignore: - 'docs/**' diff --git a/.github/workflows/functional-blockstorage.yaml b/.github/workflows/functional-blockstorage.yaml index c747d5b899..4a108b3247 100644 --- a/.github/workflows/functional-blockstorage.yaml +++ b/.github/workflows/functional-blockstorage.yaml @@ -1,5 +1,6 @@ name: functional-blockstorage on: + merge_group: pull_request: paths: - 'openstack/auth_env.go' diff --git a/.github/workflows/functional-compute.yaml b/.github/workflows/functional-compute.yaml index 516be94de5..4a684edd84 100644 --- a/.github/workflows/functional-compute.yaml +++ b/.github/workflows/functional-compute.yaml @@ -1,5 +1,6 @@ name: functional-compute on: + merge_group: pull_request: paths: - 'openstack/auth_env.go' diff --git a/.github/workflows/functional-containerinfra.yaml b/.github/workflows/functional-containerinfra.yaml index 60df8d7839..dad5a6b4d7 100644 --- a/.github/workflows/functional-containerinfra.yaml +++ b/.github/workflows/functional-containerinfra.yaml @@ -1,5 +1,6 @@ name: functional-containerinfra on: + merge_group: pull_request: paths: - 'openstack/auth_env.go' diff --git a/.github/workflows/functional-dns.yaml b/.github/workflows/functional-dns.yaml index 243cd71e8b..21879e8321 100644 --- a/.github/workflows/functional-dns.yaml +++ b/.github/workflows/functional-dns.yaml @@ -1,5 +1,6 @@ name: functional-dns on: + merge_group: pull_request: paths: - 'openstack/auth_env.go' diff --git a/.github/workflows/functional-fwaas_v2.yaml b/.github/workflows/functional-fwaas_v2.yaml index da944898ae..d7856d4571 100644 --- a/.github/workflows/functional-fwaas_v2.yaml +++ b/.github/workflows/functional-fwaas_v2.yaml @@ -4,6 +4,7 @@ # [1] https://bugs.launchpad.net/neutron/+bug/1971958 name: functional-fwaas_v2 on: + merge_group: pull_request: paths: - 'openstack/auth_env.go' diff --git a/.github/workflows/functional-identity.yaml b/.github/workflows/functional-identity.yaml index 48e605b6f5..58c9b2188f 100644 --- a/.github/workflows/functional-identity.yaml +++ b/.github/workflows/functional-identity.yaml @@ -1,5 +1,6 @@ name: functional-identity on: + merge_group: pull_request: paths: - 'openstack/auth_env.go' diff --git a/.github/workflows/functional-image.yaml b/.github/workflows/functional-image.yaml index 5de98b2d95..e4d290339f 100644 --- a/.github/workflows/functional-image.yaml +++ b/.github/workflows/functional-image.yaml @@ -1,5 +1,6 @@ name: functional-image on: + merge_group: pull_request: paths: - 'openstack/auth_env.go' diff --git a/.github/workflows/functional-keymanager.yaml b/.github/workflows/functional-keymanager.yaml index 1c3a9a0256..e1bd85c0e9 100644 --- a/.github/workflows/functional-keymanager.yaml +++ b/.github/workflows/functional-keymanager.yaml @@ -1,5 +1,6 @@ name: functional-keymanager on: + merge_group: pull_request: paths: - 'openstack/auth_env.go' diff --git a/.github/workflows/functional-loadbalancer.yaml b/.github/workflows/functional-loadbalancer.yaml index ad0071c84b..9aa8ffed3b 100644 --- a/.github/workflows/functional-loadbalancer.yaml +++ b/.github/workflows/functional-loadbalancer.yaml @@ -1,5 +1,6 @@ name: functional-loadbalancer on: + merge_group: pull_request: paths: - 'openstack/auth_env.go' diff --git a/.github/workflows/functional-messaging.yaml b/.github/workflows/functional-messaging.yaml index aad3ed9754..415c85086e 100644 --- a/.github/workflows/functional-messaging.yaml +++ b/.github/workflows/functional-messaging.yaml @@ -1,5 +1,6 @@ name: functional-messaging on: + merge_group: pull_request: paths: - 'openstack/auth_env.go' diff --git a/.github/workflows/functional-networking.yaml b/.github/workflows/functional-networking.yaml index c1a0661d92..4f57d1da57 100644 --- a/.github/workflows/functional-networking.yaml +++ b/.github/workflows/functional-networking.yaml @@ -1,5 +1,6 @@ name: functional-networking on: + merge_group: pull_request: paths: - 'openstack/auth_env.go' diff --git a/.github/workflows/functional-objectstorage.yaml b/.github/workflows/functional-objectstorage.yaml index 494e44fa1c..d484ea1b33 100644 --- a/.github/workflows/functional-objectstorage.yaml +++ b/.github/workflows/functional-objectstorage.yaml @@ -1,5 +1,6 @@ name: functional-objectstorage on: + merge_group: pull_request: paths: - 'openstack/auth_env.go' diff --git a/.github/workflows/functional-orchestration.yaml b/.github/workflows/functional-orchestration.yaml index f54f9d7a81..ca553ad82e 100644 --- a/.github/workflows/functional-orchestration.yaml +++ b/.github/workflows/functional-orchestration.yaml @@ -1,5 +1,6 @@ name: functional-orchestration on: + merge_group: pull_request: paths: - 'openstack/auth_env.go' diff --git a/.github/workflows/functional-placement.yaml b/.github/workflows/functional-placement.yaml index bacc97940d..9345989800 100644 --- a/.github/workflows/functional-placement.yaml +++ b/.github/workflows/functional-placement.yaml @@ -1,5 +1,6 @@ name: functional-placement on: + merge_group: pull_request: paths: - 'openstack/auth_env.go' diff --git a/.github/workflows/functional-sharedfilesystems.yaml b/.github/workflows/functional-sharedfilesystems.yaml index db803850de..79bb42844d 100644 --- a/.github/workflows/functional-sharedfilesystems.yaml +++ b/.github/workflows/functional-sharedfilesystems.yaml @@ -1,5 +1,6 @@ name: functional-sharedfilesystems on: + merge_group: pull_request: paths: - 'openstack/auth_env.go' diff --git a/.github/workflows/functional-workflow.yaml b/.github/workflows/functional-workflow.yaml index c0ef7839cd..2288e90e70 100644 --- a/.github/workflows/functional-workflow.yaml +++ b/.github/workflows/functional-workflow.yaml @@ -1,5 +1,6 @@ name: functional-workflow on: + merge_group: pull_request: paths: - 'openstack/auth_env.go' diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 4a627ec507..f1696959e9 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -1,5 +1,6 @@ name: Linters on: + - merge_group - push - pull_request permissions: diff --git a/.github/workflows/unit.yaml b/.github/workflows/unit.yaml index c462a6dd27..ee7eb7fd58 100644 --- a/.github/workflows/unit.yaml +++ b/.github/workflows/unit.yaml @@ -1,5 +1,6 @@ name: Unit Testing on: + - merge_group - push - pull_request permissions: From 5fb0f179be566e1a3c290661a03ecad1f92d1a35 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Mon, 1 Sep 2025 16:26:54 +0100 Subject: [PATCH 244/429] Add local GitHub action To allow us to retrieve the list of changed files in the PR and compare them against a whitelist. This filtering only happens for non-scheduled jobs. For scheduled jobs, we should always run. Signed-off-by: Stephen Finucane --- .github/actions/file-filter/Dockerfile | 5 + .github/actions/file-filter/action.yml | 24 +++ .../actions/file-filter/file_filter_action.py | 148 ++++++++++++++++++ 3 files changed, 177 insertions(+) create mode 100644 .github/actions/file-filter/Dockerfile create mode 100644 .github/actions/file-filter/action.yml create mode 100755 .github/actions/file-filter/file_filter_action.py diff --git a/.github/actions/file-filter/Dockerfile b/.github/actions/file-filter/Dockerfile new file mode 100644 index 0000000000..4994652170 --- /dev/null +++ b/.github/actions/file-filter/Dockerfile @@ -0,0 +1,5 @@ +FROM python:3.11-slim +WORKDIR /app +RUN pip install 'PyGithub~=2.7.0' 'requests~=2.32' +COPY file_filter_action.py ./ +ENTRYPOINT ["python", "/app/file_filter_action.py"] diff --git a/.github/actions/file-filter/action.yml b/.github/actions/file-filter/action.yml new file mode 100644 index 0000000000..afd9fac6c8 --- /dev/null +++ b/.github/actions/file-filter/action.yml @@ -0,0 +1,24 @@ +name: 'File Filter' +description: 'Filter PR files by glob patterns and return true/false if any files match' +inputs: + patterns: + description: 'String containing one or more glob patterns separated by spaces' + required: true + exclude: + description: 'Whether patterns is a list of glob patterns to *exclude* rather than *include*' + required: false + default: false + token: + description: 'GitHub token for API access' + required: false + default: ${{ github.token }} +outputs: + matches: + description: 'True if any files match the patterns or if event_type is schedule, false otherwise (boolean)' + count: + description: 'Number of files that matched the patterns; will be unset if event_type is schedule (integer)' + files: + description: 'Files that matched the patterns; will unset if event_type is schedule (JSON array of strings)' +runs: + using: 'docker' + image: 'Dockerfile' diff --git a/.github/actions/file-filter/file_filter_action.py b/.github/actions/file-filter/file_filter_action.py new file mode 100755 index 0000000000..75bb0960c3 --- /dev/null +++ b/.github/actions/file-filter/file_filter_action.py @@ -0,0 +1,148 @@ +#!/usr/bin/env python3 + +import argparse +import fnmatch +import json +import os +import sys + +import github + + +def parse_patterns(patterns_input: str) -> list[str]: + """Parse glob patterns from newline- or space-separated string input.""" + if not patterns_input: + return [] + + patterns = [p.strip() for p in patterns_input.split() if p.strip()] + + if not patterns: + raise ValueError('No valid patterns found in input') + + return patterns + + +def get_changed_files( + github_client: github.Github, repo_name: str, +) -> list[str]: + """Get list of changed files between base and head refs.""" + try: + repo = github_client.get_repo(repo_name) + + # Try to get PR context first + if 'GITHUB_EVENT_PATH' in os.environ: + try: + with open(os.environ['GITHUB_EVENT_PATH']) as f: + event_data = json.load(f) + + if 'pull_request' in event_data: + pr_number = event_data['pull_request']['number'] + pr = repo.get_pull(pr_number) + files = pr.get_files() + return [f.filename for f in files] + except (FileNotFoundError, KeyError, json.JSONDecodeError): + pass + + base_ref = os.environ.get('GITHUB_BASE_REF', 'main') + head_ref = os.environ.get('GITHUB_HEAD_REF', os.environ.get('GITHUB_SHA')) + + if head_ref: + comparison = repo.compare(base_ref, head_ref) + return [f.filename for f in comparison.files] + + print('Warning: Could not determine changed files', file=sys.stderr) + return [] + except github.GithubException as e: + print(f'GitHub API error: {e}', file=sys.stderr) + return [] + except Exception as e: + print(f'Error getting changed files: {e}', file=sys.stderr) + return [] + + +def match_files(files: list[str], patterns: list[str], exclude: bool) -> list[str]: + """Match files against glob patterns.""" + matches = [] + + for file_path in files: + for pattern in patterns: + if (fnmatch.fnmatch(file_path, pattern) and not exclude) or exclude: + matches.append(file_path) + break + + return matches + + +def set_output(name: str, value: str) -> None: + """Set GitHub Actions output.""" + if 'GITHUB_OUTPUT' in os.environ: + with open(os.environ['GITHUB_OUTPUT'], 'a') as f: + f.write(f'{name}={value}\n') + else: + # Fallback for older runners + print(f'::set-output name={name}::{value}') + + +def main() -> None: + """Main function.""" + parser = argparse.ArgumentParser( + description=( + 'A utility script to retrieve the list of changed files in the ' + 'current PR, intended to be run as part of a GitHub Actions ' + 'pipeline.' + ), + ) + parser.parse_args() + + try: + patterns_input = os.environ.get('INPUT_PATTERNS', '') + token = os.environ.get('INPUT_TOKEN', os.environ.get('GITHUB_TOKEN', '')) + exclude = os.environ.get('INPUT_EXCLUDE') + repo_name = os.environ.get('GITHUB_REPOSITORY', '') + event_type = os.environ.get('GITHUB_EVENT_NAME') + + print(f'Event type: {event_type}') + if event_type in ('schedule',): + print(f'Skipping file check for event_type={event_type}') + set_output('matches', 'true') + set_output('count', '') + set_output('files', '') + sys.exit(0) + + if not patterns_input: + print('Error: No patterns provided', file=sys.stderr) + sys.exit(1) + + if not token: + print('Error: No GitHub token provided', file=sys.stderr) + sys.exit(1) + + if not repo_name: + print('Error: No repository name found', file=sys.stderr) + sys.exit(1) + + if exclude and exclude not in ('true', 'false'): + print('Error: exclude must be one of: true, false', file=sys.stderr) + sys.exit(1) + + patterns = parse_patterns(patterns_input) + print(f'Parsed patterns: {patterns}') + + github_client = github.Github(token) + changed_files = get_changed_files(github_client, repo_name) + matched_files = match_files(changed_files, patterns, exclude == 'true') + + print(f'Has matches? {"true" if matched_files else "false"}') + print(f'Matched files: {matched_files}') + + set_output('matches', 'true' if matched_files else 'false') + set_output('count', str(len(matched_files))) + set_output('files', json.dumps(matched_files)) + sys.exit(0) + except Exception as e: + print(f'Error: {e}', file=sys.stderr) + sys.exit(1) + + +if __name__ == '__main__': + main() From 23eae2cf8c936e4a8c41bb6955c053ca2dc52a63 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Mon, 11 Aug 2025 18:20:50 +0100 Subject: [PATCH 245/429] Always run functional tests Inspired by [1]. [1] https://brunoscheufler.com/blog/2022-04-24-required-github-actions-jobs-in-a-monorepo Signed-off-by: Stephen Finucane --- .github/workflows/functional-baremetal.yaml | 56 +++++++++++++++---- .github/workflows/functional-basic.yaml | 45 ++++++++++++--- .../workflows/functional-blockstorage.yaml | 54 ++++++++++++++---- .github/workflows/functional-compute.yaml | 54 ++++++++++++++---- .../workflows/functional-containerinfra.yaml | 54 ++++++++++++++---- .github/workflows/functional-dns.yaml | 54 ++++++++++++++---- .github/workflows/functional-fwaas_v2.yaml | 56 +++++++++++++++---- .github/workflows/functional-identity.yaml | 54 ++++++++++++++---- .github/workflows/functional-image.yaml | 54 ++++++++++++++---- .github/workflows/functional-keymanager.yaml | 54 ++++++++++++++---- .../workflows/functional-loadbalancer.yaml | 54 ++++++++++++++---- .github/workflows/functional-messaging.yaml | 54 ++++++++++++++---- .github/workflows/functional-networking.yaml | 56 +++++++++++++++---- .../workflows/functional-objectstorage.yaml | 54 ++++++++++++++---- .../workflows/functional-orchestration.yaml | 54 ++++++++++++++---- .github/workflows/functional-placement.yaml | 54 ++++++++++++++---- .../functional-sharedfilesystems.yaml | 54 ++++++++++++++---- .github/workflows/functional-workflow.yaml | 54 ++++++++++++++---- 18 files changed, 758 insertions(+), 211 deletions(-) diff --git a/.github/workflows/functional-baremetal.yaml b/.github/workflows/functional-baremetal.yaml index de497cfd3c..b4caf40994 100644 --- a/.github/workflows/functional-baremetal.yaml +++ b/.github/workflows/functional-baremetal.yaml @@ -2,16 +2,6 @@ name: functional-baremetal on: merge_group: pull_request: - paths: - - 'openstack/auth_env.go' - - 'openstack/client.go' - - 'openstack/endpoint.go' - - 'openstack/endpoint_location.go' - - 'openstack/config/provider_client.go' - - 'openstack/utils/choose_version.go' - - 'openstack/utils/discovery.go' - - '**baremetal**' - - '.github/workflows/functional-baremetal.yaml' schedule: - cron: '0 0 */3 * *' jobs: @@ -41,9 +31,34 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v5 + + - name: Check changed files + uses: ./.github/actions/file-filter + id: changed-files + with: + patterns: | + openstack/auth_env.go + openstack/client.go + openstack/endpoint.go + openstack/endpoint_location.go + openstack/config/provider_client.go + openstack/utils/choose_version.go + openstack/utils/discovery.go + **baremetal** + .github/workflows/functional-baremetal.yaml + + - name: Skip tests for unrelated changed-files + if: ${{ ! fromJSON(steps.changed-files.outputs.matches) }} + run: | + echo "No relevant files changed - skipping tests for ${{ matrix.name }}" + echo "TESTS_SKIPPED=true" >> $GITHUB_ENV + - name: Work around broken dnsmasq + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} run: sudo apt-get purge -y dnsmasq-base + - name: Deploy devstack + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: branch: ${{ matrix.openstack_version }} @@ -82,25 +97,42 @@ jobs: SWIFT_ENABLE_TEMPURLS=True SWIFT_TEMPURL_KEY=secretkey enabled_services: "ir-api,ir-cond,s-account,s-container,s-object,s-proxy,q-svc,q-agt,q-dhcp,q-l3,q-meta,-cinder,-c-sch,-c-api,-c-vol,-c-bak,-ovn,-ovn-controller,-ovn-northd,-q-ovn-metadata-agent,${{ matrix.additional_services }}" + - name: Checkout go + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: actions/setup-go@v5 with: go-version-file: 'go.mod' cache: true + - name: Run Gophercloud acceptance tests + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} run: | source ${{ github.workspace }}/script/stackenv make acceptance-baremetal + echo "TESTS_RUN=true" >> $GITHUB_ENV env: DEVSTACK_PATH: ${{ github.workspace }}/devstack OS_BRANCH: ${{ matrix.openstack_version }} USE_SYSTEM_SCOPE: true + - name: Generate logs on failure run: ./script/collectlogs - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} + - name: Upload logs artifacts on failure - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} uses: actions/upload-artifact@v4 with: name: functional-baremetal-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* + + - name: Set job status + run: | + if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + echo "Job completed successfully (either ran tests or skipped appropriately)" + exit 0 + else + echo "Job failed - neither tests ran nor were properly skipped" + exit 1 + fi diff --git a/.github/workflows/functional-basic.yaml b/.github/workflows/functional-basic.yaml index 3e87b70194..756c742cc2 100644 --- a/.github/workflows/functional-basic.yaml +++ b/.github/workflows/functional-basic.yaml @@ -2,11 +2,6 @@ name: functional-basic on: merge_group: pull_request: - paths-ignore: - - 'docs/**' - - '**.md' - - '**.gitignore' - - '**LICENSE' schedule: - cron: '0 0 */3 * *' jobs: @@ -36,29 +31,65 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v5 + + - name: Check changed files + uses: ./.github/actions/file-filter + id: changed-files + with: + patterns: | + docs/** + **.md + **.gitignore + **LICENSE + exclude: true + + - name: Skip tests for unrelated changed-files + if: ${{ ! fromJSON(steps.changed-files.outputs.matches) }} + run: | + echo "No relevant files changed - skipping tests for ${{ matrix.name }}" + echo "TESTS_SKIPPED=true" >> $GITHUB_ENV + - name: Deploy devstack + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: branch: ${{ matrix.openstack_version }} enabled_services: 's-account,s-container,s-object,s-proxy,${{ matrix.additional_services }}' + - name: Checkout go + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: actions/setup-go@v5 with: go-version-file: 'go.mod' cache: true + - name: Run Gophercloud acceptance tests + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} run: | source ${{ github.workspace }}/script/stackenv make acceptance-basic + echo "TESTS_RUN=true" >> $GITHUB_ENV env: DEVSTACK_PATH: ${{ github.workspace }}/devstack OS_BRANCH: ${{ matrix.openstack_version }} + - name: Generate logs on failure run: ./script/collectlogs - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} + - name: Upload logs artifacts on failure - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} uses: actions/upload-artifact@v4 with: name: functional-basic-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* + + - name: Set job status + run: | + if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + echo "Job completed successfully (either ran tests or skipped appropriately)" + exit 0 + else + echo "Job failed - neither tests ran nor were properly skipped" + exit 1 + fi diff --git a/.github/workflows/functional-blockstorage.yaml b/.github/workflows/functional-blockstorage.yaml index 4a108b3247..7c4ab14bac 100644 --- a/.github/workflows/functional-blockstorage.yaml +++ b/.github/workflows/functional-blockstorage.yaml @@ -2,16 +2,6 @@ name: functional-blockstorage on: merge_group: pull_request: - paths: - - 'openstack/auth_env.go' - - 'openstack/client.go' - - 'openstack/endpoint.go' - - 'openstack/endpoint_location.go' - - 'openstack/config/provider_client.go' - - 'openstack/utils/choose_version.go' - - 'openstack/utils/discovery.go' - - '**blockstorage**' - - '.github/workflows/functional-blockstorage.yaml' schedule: - cron: '0 0 */3 * *' jobs: @@ -41,31 +31,71 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v5 + + - name: Check changed files + uses: ./.github/actions/file-filter + id: changed-files + with: + patterns: | + openstack/auth_env.go + openstack/client.go + openstack/endpoint.go + openstack/endpoint_location.go + openstack/config/provider_client.go + openstack/utils/choose_version.go + openstack/utils/discovery.go + **blockstorage** + .github/workflows/functional-blockstorage.yaml + + - name: Skip tests for unrelated changed-files + if: ${{ ! fromJSON(steps.changed-files.outputs.matches) }} + run: | + echo "No relevant files changed - skipping tests for ${{ matrix.name }}" + echo "TESTS_SKIPPED=true" >> $GITHUB_ENV + - name: Deploy devstack + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: branch: ${{ matrix.openstack_version }} conf_overrides: | CINDER_ISCSI_HELPER=lioadm enabled_services: "s-account,s-container,s-object,s-proxy,c-bak,${{ matrix.additional_services }}" + - name: Checkout go + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: actions/setup-go@v5 with: go-version-file: 'go.mod' cache: true + - name: Run Gophercloud acceptance tests + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} run: | source ${{ github.workspace }}/script/stackenv make acceptance-blockstorage + echo "TESTS_RUN=true" >> $GITHUB_ENV env: DEVSTACK_PATH: ${{ github.workspace }}/devstack OS_BRANCH: ${{ matrix.openstack_version }} + - name: Generate logs on failure run: ./script/collectlogs - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} + - name: Upload logs artifacts on failure - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} uses: actions/upload-artifact@v4 with: name: functional-blockstorage-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* + + - name: Set job status + run: | + if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + echo "Job completed successfully (either ran tests or skipped appropriately)" + exit 0 + else + echo "Job failed - neither tests ran nor were properly skipped" + exit 1 + fi diff --git a/.github/workflows/functional-compute.yaml b/.github/workflows/functional-compute.yaml index 4a684edd84..8d932e44b5 100644 --- a/.github/workflows/functional-compute.yaml +++ b/.github/workflows/functional-compute.yaml @@ -2,16 +2,6 @@ name: functional-compute on: merge_group: pull_request: - paths: - - 'openstack/auth_env.go' - - 'openstack/client.go' - - 'openstack/endpoint.go' - - 'openstack/endpoint_location.go' - - 'openstack/config/provider_client.go' - - 'openstack/utils/choose_version.go' - - 'openstack/utils/discovery.go' - - '**compute**' - - '.github/workflows/functional-compute.yaml' schedule: - cron: '0 0 */3 * *' jobs: @@ -41,31 +31,71 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v5 + + - name: Check changed files + uses: ./.github/actions/file-filter + id: changed-files + with: + patterns: | + openstack/auth_env.go + openstack/client.go + openstack/endpoint.go + openstack/endpoint_location.go + openstack/config/provider_client.go + openstack/utils/choose_version.go + openstack/utils/discovery.go + **compute** + .github/workflows/functional-compute.yaml + + - name: Skip tests for unrelated changed-files + if: ${{ ! fromJSON(steps.changed-files.outputs.matches) }} + run: | + echo "No relevant files changed - skipping tests for ${{ matrix.name }}" + echo "TESTS_SKIPPED=true" >> $GITHUB_ENV + - name: Deploy devstack + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: branch: ${{ matrix.openstack_version }} conf_overrides: | CINDER_ISCSI_HELPER=lioadm enabled_services: "${{ matrix.additional_services }}" + - name: Checkout go + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: actions/setup-go@v5 with: go-version-file: 'go.mod' cache: true + - name: Run Gophercloud acceptance tests + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} run: | source ${{ github.workspace }}/script/stackenv make acceptance-compute + echo "TESTS_RUN=true" >> $GITHUB_ENV env: DEVSTACK_PATH: ${{ github.workspace }}/devstack OS_BRANCH: ${{ matrix.openstack_version }} + - name: Generate logs on failure run: ./script/collectlogs - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} + - name: Upload logs artifacts on failure - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} uses: actions/upload-artifact@v4 with: name: functional-compute-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* + + - name: Set job status + run: | + if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + echo "Job completed successfully (either ran tests or skipped appropriately)" + exit 0 + else + echo "Job failed - neither tests ran nor were properly skipped" + exit 1 + fi diff --git a/.github/workflows/functional-containerinfra.yaml b/.github/workflows/functional-containerinfra.yaml index dad5a6b4d7..bca3ee49b0 100644 --- a/.github/workflows/functional-containerinfra.yaml +++ b/.github/workflows/functional-containerinfra.yaml @@ -2,16 +2,6 @@ name: functional-containerinfra on: merge_group: pull_request: - paths: - - 'openstack/auth_env.go' - - 'openstack/client.go' - - 'openstack/endpoint.go' - - 'openstack/endpoint_location.go' - - 'openstack/config/provider_client.go' - - 'openstack/utils/choose_version.go' - - 'openstack/utils/discovery.go' - - '**containerinfra**' - - '.github/workflows/functional-containerinfra.yaml' schedule: - cron: '0 0 */3 * *' jobs: @@ -65,7 +55,30 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v5 + + - name: Check changed files + uses: ./.github/actions/file-filter + id: changed-files + with: + patterns: | + openstack/auth_env.go + openstack/client.go + openstack/endpoint.go + openstack/endpoint_location.go + openstack/config/provider_client.go + openstack/utils/choose_version.go + openstack/utils/discovery.go + **containerinfra** + .github/workflows/functional-containerinfra.yaml + + - name: Skip tests for unrelated changed-files + if: ${{ ! fromJSON(steps.changed-files.outputs.matches) }} + run: | + echo "No relevant files changed - skipping tests for ${{ matrix.name }}" + echo "TESTS_SKIPPED=true" >> $GITHUB_ENV + - name: Deploy devstack + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: branch: ${{ matrix.openstack_version }} @@ -78,24 +91,41 @@ jobs: ${{ matrix.devstack_conf_overrides }} enabled_services: "h-eng,h-api,h-api-cfn,h-api-cw,${{ matrix.additional_services }}" + - name: Checkout go + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: actions/setup-go@v5 with: go-version-file: 'go.mod' cache: true + - name: Run Gophercloud acceptance tests + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} run: | source ${{ github.workspace }}/script/stackenv make acceptance-containerinfra + echo "TESTS_RUN=true" >> $GITHUB_ENV env: DEVSTACK_PATH: ${{ github.workspace }}/devstack OS_BRANCH: ${{ matrix.openstack_version }} + - name: Generate logs on failure run: ./script/collectlogs - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} + - name: Upload logs artifacts on failure - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} uses: actions/upload-artifact@v4 with: name: functional-containerinfra-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* + + - name: Set job status + run: | + if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + echo "Job completed successfully (either ran tests or skipped appropriately)" + exit 0 + else + echo "Job failed - neither tests ran nor were properly skipped" + exit 1 + fi diff --git a/.github/workflows/functional-dns.yaml b/.github/workflows/functional-dns.yaml index 21879e8321..51adcd0535 100644 --- a/.github/workflows/functional-dns.yaml +++ b/.github/workflows/functional-dns.yaml @@ -2,16 +2,6 @@ name: functional-dns on: merge_group: pull_request: - paths: - - 'openstack/auth_env.go' - - 'openstack/client.go' - - 'openstack/endpoint.go' - - 'openstack/endpoint_location.go' - - 'openstack/config/provider_client.go' - - 'openstack/utils/choose_version.go' - - 'openstack/utils/discovery.go' - - '**dns**' - - '.github/workflows/functional-dns.yaml' schedule: - cron: '0 0 */3 * *' jobs: @@ -47,7 +37,30 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v5 + + - name: Check changed files + uses: ./.github/actions/file-filter + id: changed-files + with: + patterns: | + openstack/auth_env.go + openstack/client.go + openstack/endpoint.go + openstack/endpoint_location.go + openstack/config/provider_client.go + openstack/utils/choose_version.go + openstack/utils/discovery.go + **dns** + .github/workflows/functional-dns.yaml + + - name: Skip tests for unrelated changed-files + if: ${{ ! fromJSON(steps.changed-files.outputs.matches) }} + run: | + echo "No relevant files changed - skipping tests for ${{ matrix.name }}" + echo "TESTS_SKIPPED=true" >> $GITHUB_ENV + - name: Deploy devstack + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: branch: ${{ matrix.openstack_version }} @@ -56,24 +69,41 @@ jobs: ${{ matrix.devstack_conf_overrides }} enabled_services: "designate,designate-central,designate-api,designate-worker,designate-producer,designate-mdns,${{ matrix.additional_services }}" + - name: Checkout go + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: actions/setup-go@v5 with: go-version-file: 'go.mod' cache: true + - name: Run Gophercloud acceptance tests + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} run: | source ${{ github.workspace }}/script/stackenv make acceptance-dns + echo "TESTS_RUN=true" >> $GITHUB_ENV env: DEVSTACK_PATH: ${{ github.workspace }}/devstack OS_BRANCH: ${{ matrix.openstack_version }} + - name: Generate logs on failure run: ./script/collectlogs - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} + - name: Upload logs artifacts on failure - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} uses: actions/upload-artifact@v4 with: name: functional-dns-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* + + - name: Set job status + run: | + if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + echo "Job completed successfully (either ran tests or skipped appropriately)" + exit 0 + else + echo "Job failed - neither tests ran nor were properly skipped" + exit 1 + fi diff --git a/.github/workflows/functional-fwaas_v2.yaml b/.github/workflows/functional-fwaas_v2.yaml index d7856d4571..3fd3e971eb 100644 --- a/.github/workflows/functional-fwaas_v2.yaml +++ b/.github/workflows/functional-fwaas_v2.yaml @@ -6,16 +6,6 @@ name: functional-fwaas_v2 on: merge_group: pull_request: - paths: - - 'openstack/auth_env.go' - - 'openstack/client.go' - - 'openstack/endpoint.go' - - 'openstack/endpoint_location.go' - - 'openstack/config/provider_client.go' - - 'openstack/utils/choose_version.go' - - 'openstack/utils/discovery.go' - - '**networking/v2/extensions/fwaas_v2**' - - '.github/workflows/functional-fwaas_v2.yaml' schedule: - cron: '0 0 */3 * *' jobs: @@ -45,7 +35,30 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v5 + + - name: Check changed files + uses: ./.github/actions/file-filter + id: changed-files + with: + patterns: | + openstack/auth_env.go + openstack/client.go + openstack/endpoint.go + openstack/endpoint_location.go + openstack/config/provider_client.go + openstack/utils/choose_version.go + openstack/utils/discovery.go + **networking/v2/extensions/fwaas_v2** + .github/workflows/functional-fwaas_v2.yaml + + - name: Skip tests for unrelated changed-files + if: ${{ ! fromJSON(steps.changed-files.outputs.matches) }} + run: | + echo "No relevant files changed - skipping tests for ${{ matrix.name }}" + echo "TESTS_SKIPPED=true" >> $GITHUB_ENV + - name: Create additional neutron policies + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} run: | mkdir /tmp/neutron-policies cat << EOF >> /tmp/neutron-policies/port_binding.yaml @@ -53,7 +66,9 @@ jobs: "create_port:binding:profile": "rule:admin_only or rule:service_api" "update_port:binding:profile": "rule:admin_only or rule:service_api" EOF + - name: Deploy devstack + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: branch: ${{ matrix.openstack_version }} @@ -69,24 +84,41 @@ jobs: [oslo_policy] policy_dirs = /tmp/neutron-policies enabled_services: 'q-svc,q-agt,q-dhcp,q-l3,q-meta,q-fwaas-v2,-cinder,-horizon,-tempest,-swift,-c-sch,-c-api,-c-vol,-c-bak,-ovn,-ovn-controller,-ovn-northd,-q-ovn-metadata-agent,${{ matrix.additional_services }}' + - name: Checkout go + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: actions/setup-go@v5 with: go-version-file: 'go.mod' cache: true + - name: Run Gophercloud acceptance tests + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} run: | source ${{ github.workspace }}/script/stackenv make acceptance-networking + echo "TESTS_RUN=true" >> $GITHUB_ENV env: DEVSTACK_PATH: ${{ github.workspace }}/devstack OS_BRANCH: ${{ matrix.openstack_version }} + - name: Generate logs on failure run: ./script/collectlogs - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} + - name: Upload logs artifacts on failure - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} uses: actions/upload-artifact@v4 with: name: functional-fwaas_v2-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* + + - name: Set job status + run: | + if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + echo "Job completed successfully (either ran tests or skipped appropriately)" + exit 0 + else + echo "Job failed - neither tests ran nor were properly skipped" + exit 1 + fi diff --git a/.github/workflows/functional-identity.yaml b/.github/workflows/functional-identity.yaml index 58c9b2188f..f1c920981b 100644 --- a/.github/workflows/functional-identity.yaml +++ b/.github/workflows/functional-identity.yaml @@ -2,16 +2,6 @@ name: functional-identity on: merge_group: pull_request: - paths: - - 'openstack/auth_env.go' - - 'openstack/client.go' - - 'openstack/endpoint.go' - - 'openstack/endpoint_location.go' - - 'openstack/config/provider_client.go' - - 'openstack/utils/choose_version.go' - - 'openstack/utils/discovery.go' - - '**identity**' - - '.github/workflows/functional-identity.yaml' schedule: - cron: '0 0 */3 * *' jobs: @@ -41,29 +31,69 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v5 + + - name: Check changed files + uses: ./.github/actions/file-filter + id: changed-files + with: + patterns: | + openstack/auth_env.go + openstack/client.go + openstack/endpoint.go + openstack/endpoint_location.go + openstack/config/provider_client.go + openstack/utils/choose_version.go + openstack/utils/discovery.go + **identity** + .github/workflows/functional-identity.yaml + + - name: Skip tests for unrelated changed-files + if: ${{ ! fromJSON(steps.changed-files.outputs.matches) }} + run: | + echo "No relevant files changed - skipping tests for ${{ matrix.name }}" + echo "TESTS_SKIPPED=true" >> $GITHUB_ENV + - name: Deploy devstack + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: branch: ${{ matrix.openstack_version }} enabled_services: "${{ matrix.additional_services }}" + - name: Checkout go + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: actions/setup-go@v5 with: go-version-file: 'go.mod' cache: true + - name: Run Gophercloud acceptance tests + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} run: | source ${{ github.workspace }}/script/stackenv make acceptance-identity + echo "TESTS_RUN=true" >> $GITHUB_ENV env: DEVSTACK_PATH: ${{ github.workspace }}/devstack OS_BRANCH: ${{ matrix.openstack_version }} + - name: Generate logs on failure run: ./script/collectlogs - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} + - name: Upload logs artifacts on failure - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} uses: actions/upload-artifact@v4 with: name: functional-identity-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* + + - name: Set job status + run: | + if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + echo "Job completed successfully (either ran tests or skipped appropriately)" + exit 0 + else + echo "Job failed - neither tests ran nor were properly skipped" + exit 1 + fi diff --git a/.github/workflows/functional-image.yaml b/.github/workflows/functional-image.yaml index e4d290339f..eb299c93b3 100644 --- a/.github/workflows/functional-image.yaml +++ b/.github/workflows/functional-image.yaml @@ -2,16 +2,6 @@ name: functional-image on: merge_group: pull_request: - paths: - - 'openstack/auth_env.go' - - 'openstack/client.go' - - 'openstack/endpoint.go' - - 'openstack/endpoint_location.go' - - 'openstack/config/provider_client.go' - - 'openstack/utils/choose_version.go' - - 'openstack/utils/discovery.go' - - '**image**' - - '.github/workflows/functional-image.yaml' schedule: - cron: '0 0 */3 * *' jobs: @@ -41,29 +31,69 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v5 + + - name: Check changed files + uses: ./.github/actions/file-filter + id: changed-files + with: + patterns: | + openstack/auth_env.go + openstack/client.go + openstack/endpoint.go + openstack/endpoint_location.go + openstack/config/provider_client.go + openstack/utils/choose_version.go + openstack/utils/discovery.go + **image** + .github/workflows/functional-image.yaml + + - name: Skip tests for unrelated changed-files + if: ${{ ! fromJSON(steps.changed-files.outputs.matches) }} + run: | + echo "No relevant files changed - skipping tests for ${{ matrix.name }}" + echo "TESTS_SKIPPED=true" >> $GITHUB_ENV + - name: Deploy devstack + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: branch: ${{ matrix.openstack_version }} enabled_services: "${{ matrix.additional_services }}" + - name: Checkout go + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: actions/setup-go@v5 with: go-version-file: 'go.mod' cache: true + - name: Run Gophercloud acceptance tests + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} run: | source ${{ github.workspace }}/script/stackenv make acceptance-image + echo "TESTS_RUN=true" >> $GITHUB_ENV env: DEVSTACK_PATH: ${{ github.workspace }}/devstack OS_BRANCH: ${{ matrix.openstack_version }} + - name: Generate logs on failure run: ./script/collectlogs - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} + - name: Upload logs artifacts on failure - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} uses: actions/upload-artifact@v4 with: name: functional-image-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* + + - name: Set job status + run: | + if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + echo "Job completed successfully (either ran tests or skipped appropriately)" + exit 0 + else + echo "Job failed - neither tests ran nor were properly skipped" + exit 1 + fi diff --git a/.github/workflows/functional-keymanager.yaml b/.github/workflows/functional-keymanager.yaml index e1bd85c0e9..b5db25d8ca 100644 --- a/.github/workflows/functional-keymanager.yaml +++ b/.github/workflows/functional-keymanager.yaml @@ -2,16 +2,6 @@ name: functional-keymanager on: merge_group: pull_request: - paths: - - 'openstack/auth_env.go' - - 'openstack/client.go' - - 'openstack/endpoint.go' - - 'openstack/endpoint_location.go' - - 'openstack/config/provider_client.go' - - 'openstack/utils/choose_version.go' - - 'openstack/utils/discovery.go' - - '**keymanager**' - - '.github/workflows/functional-keymanager.yaml' schedule: - cron: '0 0 */3 * *' jobs: @@ -53,7 +43,30 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v5 + + - name: Check changed files + uses: ./.github/actions/file-filter + id: changed-files + with: + patterns: | + openstack/auth_env.go + openstack/client.go + openstack/endpoint.go + openstack/endpoint_location.go + openstack/config/provider_client.go + openstack/utils/choose_version.go + openstack/utils/discovery.go + **keymanager** + .github/workflows/functional-keymanager.yaml + + - name: Skip tests for unrelated changed-files + if: ${{ ! fromJSON(steps.changed-files.outputs.matches) }} + run: | + echo "No relevant files changed - skipping tests for ${{ matrix.name }}" + echo "TESTS_SKIPPED=true" >> $GITHUB_ENV + - name: Deploy devstack + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: branch: ${{ matrix.openstack_version }} @@ -62,24 +75,41 @@ jobs: ${{ matrix.devstack_conf_overrides }} enabled_services: "barbican-svc,barbican-retry,barbican-keystone-listener,${{ matrix.additional_services }}" + - name: Checkout go + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: actions/setup-go@v5 with: go-version-file: 'go.mod' cache: true + - name: Run Gophercloud acceptance tests + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} run: | source ${{ github.workspace }}/script/stackenv make acceptance-keymanager + echo "TESTS_RUN=true" >> $GITHUB_ENV env: DEVSTACK_PATH: ${{ github.workspace }}/devstack OS_BRANCH: ${{ matrix.openstack_version }} + - name: Generate logs on failure run: ./script/collectlogs - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} + - name: Upload logs artifacts on failure - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} uses: actions/upload-artifact@v4 with: name: functional-keymanager-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* + + - name: Set job status + run: | + if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + echo "Job completed successfully (either ran tests or skipped appropriately)" + exit 0 + else + echo "Job failed - neither tests ran nor were properly skipped" + exit 1 + fi diff --git a/.github/workflows/functional-loadbalancer.yaml b/.github/workflows/functional-loadbalancer.yaml index 9aa8ffed3b..02df282845 100644 --- a/.github/workflows/functional-loadbalancer.yaml +++ b/.github/workflows/functional-loadbalancer.yaml @@ -2,16 +2,6 @@ name: functional-loadbalancer on: merge_group: pull_request: - paths: - - 'openstack/auth_env.go' - - 'openstack/client.go' - - 'openstack/endpoint.go' - - 'openstack/endpoint_location.go' - - 'openstack/config/provider_client.go' - - 'openstack/utils/choose_version.go' - - 'openstack/utils/discovery.go' - - '**loadbalancer**' - - '.github/workflows/functional-loadbalancer.yaml' schedule: - cron: '0 0 */3 * *' jobs: @@ -47,7 +37,30 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v5 + + - name: Check changed files + uses: ./.github/actions/file-filter + id: changed-files + with: + patterns: | + openstack/auth_env.go + openstack/client.go + openstack/endpoint.go + openstack/endpoint_location.go + openstack/config/provider_client.go + openstack/utils/choose_version.go + openstack/utils/discovery.go + **loadbalancer** + .github/workflows/functional-loadbalancer.yaml + + - name: Skip tests for unrelated changed-files + if: ${{ ! fromJSON(steps.changed-files.outputs.matches) }} + run: | + echo "No relevant files changed - skipping tests for ${{ matrix.name }}" + echo "TESTS_SKIPPED=true" >> $GITHUB_ENV + - name: Deploy devstack + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: branch: ${{ matrix.openstack_version }} @@ -57,24 +70,41 @@ jobs: ${{ matrix.devstack_conf_overrides }} enabled_services: "octavia,o-api,o-cw,o-hk,o-hm,o-da,neutron-qos,${{ matrix.additional_services }}" + - name: Checkout go + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: actions/setup-go@v5 with: go-version-file: 'go.mod' cache: true + - name: Run Gophercloud acceptance tests + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} run: | source ${{ github.workspace }}/script/stackenv make acceptance-loadbalancer + echo "TESTS_RUN=true" >> $GITHUB_ENV env: DEVSTACK_PATH: ${{ github.workspace }}/devstack OS_BRANCH: ${{ matrix.openstack_version }} + - name: Generate logs on failure run: ./script/collectlogs - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} + - name: Upload logs artifacts on failure - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} uses: actions/upload-artifact@v4 with: name: functional-loadbalancer-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* + + - name: Set job status + run: | + if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + echo "Job completed successfully (either ran tests or skipped appropriately)" + exit 0 + else + echo "Job failed - neither tests ran nor were properly skipped" + exit 1 + fi diff --git a/.github/workflows/functional-messaging.yaml b/.github/workflows/functional-messaging.yaml index 415c85086e..7f8ef7cc8e 100644 --- a/.github/workflows/functional-messaging.yaml +++ b/.github/workflows/functional-messaging.yaml @@ -2,16 +2,6 @@ name: functional-messaging on: merge_group: pull_request: - paths: - - 'openstack/auth_env.go' - - 'openstack/client.go' - - 'openstack/endpoint.go' - - 'openstack/endpoint_location.go' - - 'openstack/config/provider_client.go' - - 'openstack/utils/choose_version.go' - - 'openstack/utils/discovery.go' - - '**messaging**' - - '.github/workflows/functional-messaging.yaml' schedule: - cron: '0 0 */3 * *' jobs: @@ -41,7 +31,30 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v5 + + - name: Check changed files + uses: ./.github/actions/file-filter + id: changed-files + with: + patterns: | + openstack/auth_env.go + openstack/client.go + openstack/endpoint.go + openstack/endpoint_location.go + openstack/config/provider_client.go + openstack/utils/choose_version.go + openstack/utils/discovery.go + **messaging** + .github/workflows/functional-messaging.yaml + + - name: Skip tests for unrelated changed-files + if: ${{ ! fromJSON(steps.changed-files.outputs.matches) }} + run: | + echo "No relevant files changed - skipping tests for ${{ matrix.name }}" + echo "TESTS_SKIPPED=true" >> $GITHUB_ENV + - name: Deploy devstack + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: branch: ${{ matrix.openstack_version }} @@ -49,24 +62,41 @@ jobs: enable_plugin zaqar https://github.com/openstack/zaqar ${{ matrix.openstack_version }} ZAQARCLIENT_BRANCH=${{ matrix.openstack_version }} enabled_services: "${{ matrix.additional_services }}" + - name: Checkout go + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: actions/setup-go@v5 with: go-version-file: 'go.mod' cache: true + - name: Run Gophercloud acceptance tests + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} run: | source ${{ github.workspace }}/script/stackenv make acceptance-messaging + echo "TESTS_RUN=true" >> $GITHUB_ENV env: DEVSTACK_PATH: ${{ github.workspace }}/devstack OS_BRANCH: ${{ matrix.openstack_version }} + - name: Generate logs on failure run: ./script/collectlogs - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} + - name: Upload logs artifacts on failure - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} uses: actions/upload-artifact@v4 with: name: functional-messaging-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* + + - name: Set job status + run: | + if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + echo "Job completed successfully (either ran tests or skipped appropriately)" + exit 0 + else + echo "Job failed - neither tests ran nor were properly skipped" + exit 1 + fi diff --git a/.github/workflows/functional-networking.yaml b/.github/workflows/functional-networking.yaml index 4f57d1da57..4ae22544f0 100644 --- a/.github/workflows/functional-networking.yaml +++ b/.github/workflows/functional-networking.yaml @@ -2,16 +2,6 @@ name: functional-networking on: merge_group: pull_request: - paths: - - 'openstack/auth_env.go' - - 'openstack/client.go' - - 'openstack/endpoint.go' - - 'openstack/endpoint_location.go' - - 'openstack/config/provider_client.go' - - 'openstack/utils/choose_version.go' - - 'openstack/utils/discovery.go' - - '**networking**' - - '.github/workflows/functional-networking.yaml' schedule: - cron: '0 0 */3 * *' jobs: @@ -41,7 +31,30 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v5 + + - name: Check changed files + uses: ./.github/actions/file-filter + id: changed-files + with: + patterns: | + openstack/auth_env.go + openstack/client.go + openstack/endpoint.go + openstack/endpoint_location.go + openstack/config/provider_client.go + openstack/utils/choose_version.go + openstack/utils/discovery.go + **networking** + .github/workflows/functional-networking.yaml + + - name: Skip tests for unrelated changed-files + if: ${{ ! fromJSON(steps.changed-files.outputs.matches) }} + run: | + echo "No relevant files changed - skipping tests for ${{ matrix.name }}" + echo "TESTS_SKIPPED=true" >> $GITHUB_ENV + - name: Create additional neutron policies + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} run: | mkdir /tmp/neutron-policies cat << EOF >> /tmp/neutron-policies/port_binding.yaml @@ -49,7 +62,9 @@ jobs: "create_port:binding:profile": "rule:admin_only or rule:service_api" "update_port:binding:profile": "rule:admin_only or rule:service_api" EOF + - name: Deploy devstack + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: branch: ${{ matrix.openstack_version }} @@ -64,24 +79,41 @@ jobs: [oslo_policy] policy_dirs = /tmp/neutron-policies enabled_services: "neutron-dns,neutron-qos,neutron-segments,neutron-trunk,neutron-uplink-status-propagation,neutron-network-segment-range,neutron-port-forwarding,${{ matrix.additional_services }}" + - name: Checkout go + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: actions/setup-go@v5 with: go-version-file: 'go.mod' cache: true + - name: Run Gophercloud acceptance tests + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} run: | source ${{ github.workspace }}/script/stackenv make acceptance-networking + echo "TESTS_RUN=true" >> $GITHUB_ENV env: DEVSTACK_PATH: ${{ github.workspace }}/devstack OS_BRANCH: ${{ matrix.openstack_version }} + - name: Generate logs on failure run: ./script/collectlogs - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} + - name: Upload logs artifacts on failure - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} uses: actions/upload-artifact@v4 with: name: functional-networking-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* + + - name: Set job status + run: | + if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + echo "Job completed successfully (either ran tests or skipped appropriately)" + exit 0 + else + echo "Job failed - neither tests ran nor were properly skipped" + exit 1 + fi diff --git a/.github/workflows/functional-objectstorage.yaml b/.github/workflows/functional-objectstorage.yaml index d484ea1b33..38d37a793e 100644 --- a/.github/workflows/functional-objectstorage.yaml +++ b/.github/workflows/functional-objectstorage.yaml @@ -2,16 +2,6 @@ name: functional-objectstorage on: merge_group: pull_request: - paths: - - 'openstack/auth_env.go' - - 'openstack/client.go' - - 'openstack/endpoint.go' - - 'openstack/endpoint_location.go' - - 'openstack/config/provider_client.go' - - 'openstack/utils/choose_version.go' - - 'openstack/utils/discovery.go' - - '**objectstorage**' - - '.github/workflows/functional-objectstorage.yaml' schedule: - cron: '0 0 */3 * *' jobs: @@ -41,7 +31,30 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v5 + + - name: Check changed files + uses: ./.github/actions/file-filter + id: changed-files + with: + patterns: | + openstack/auth_env.go + openstack/client.go + openstack/endpoint.go + openstack/endpoint_location.go + openstack/config/provider_client.go + openstack/utils/choose_version.go + openstack/utils/discovery.go + **objectstorage** + .github/workflows/functional-objectstorage.yaml + + - name: Skip tests for unrelated changed-files + if: ${{ ! fromJSON(steps.changed-files.outputs.matches) }} + run: | + echo "No relevant files changed - skipping tests for ${{ matrix.name }}" + echo "TESTS_SKIPPED=true" >> $GITHUB_ENV + - name: Deploy devstack + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: branch: ${{ matrix.openstack_version }} @@ -52,24 +65,41 @@ jobs: [filter:versioned_writes] allow_object_versioning = true enabled_services: 's-account,s-container,s-object,s-proxy,${{ matrix.additional_services }}' + - name: Checkout go + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: actions/setup-go@v5 with: go-version-file: 'go.mod' cache: true + - name: Run Gophercloud acceptance tests + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} run: | source ${{ github.workspace }}/script/stackenv make acceptance-objectstorage + echo "TESTS_RUN=true" >> $GITHUB_ENV env: DEVSTACK_PATH: ${{ github.workspace }}/devstack OS_BRANCH: ${{ matrix.openstack_version }} + - name: Generate logs on failure run: ./script/collectlogs - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} + - name: Upload logs artifacts on failure - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} uses: actions/upload-artifact@v4 with: name: functional-objectstorage-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* + + - name: Set job status + run: | + if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + echo "Job completed successfully (either ran tests or skipped appropriately)" + exit 0 + else + echo "Job failed - neither tests ran nor were properly skipped" + exit 1 + fi diff --git a/.github/workflows/functional-orchestration.yaml b/.github/workflows/functional-orchestration.yaml index ca553ad82e..4322089751 100644 --- a/.github/workflows/functional-orchestration.yaml +++ b/.github/workflows/functional-orchestration.yaml @@ -2,16 +2,6 @@ name: functional-orchestration on: merge_group: pull_request: - paths: - - 'openstack/auth_env.go' - - 'openstack/client.go' - - 'openstack/endpoint.go' - - 'openstack/endpoint_location.go' - - 'openstack/config/provider_client.go' - - 'openstack/utils/choose_version.go' - - 'openstack/utils/discovery.go' - - '**orchestration**' - - '.github/workflows/functional-orchestration.yaml' schedule: - cron: '0 0 */3 * *' jobs: @@ -41,31 +31,71 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v5 + + - name: Check changed files + uses: ./.github/actions/file-filter + id: changed-files + with: + patterns: | + openstack/auth_env.go + openstack/client.go + openstack/endpoint.go + openstack/endpoint_location.go + openstack/config/provider_client.go + openstack/utils/choose_version.go + openstack/utils/discovery.go + **orchestration** + .github/workflows/functional-orchestration.yaml + + - name: Skip tests for unrelated changed-files + if: ${{ ! fromJSON(steps.changed-files.outputs.matches) }} + run: | + echo "No relevant files changed - skipping tests for ${{ matrix.name }}" + echo "TESTS_SKIPPED=true" >> $GITHUB_ENV + - name: Deploy devstack + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: branch: ${{ matrix.openstack_version }} conf_overrides: | enable_plugin heat https://github.com/openstack/heat ${{ matrix.openstack_version }} enabled_services: 'h-eng,h-api,h-api-cfn,h-api-cw,${{ matrix.additional_services }}' + - name: Checkout go + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: actions/setup-go@v5 with: go-version-file: 'go.mod' cache: true + - name: Run Gophercloud acceptance tests + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} run: | source ${{ github.workspace }}/script/stackenv make acceptance-orchestration + echo "TESTS_RUN=true" >> $GITHUB_ENV env: DEVSTACK_PATH: ${{ github.workspace }}/devstack OS_BRANCH: ${{ matrix.openstack_version }} + - name: Generate logs on failure run: ./script/collectlogs - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} + - name: Upload logs artifacts on failure - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} uses: actions/upload-artifact@v4 with: name: functional-orchestration-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* + + - name: Set job status + run: | + if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + echo "Job completed successfully (either ran tests or skipped appropriately)" + exit 0 + else + echo "Job failed - neither tests ran nor were properly skipped" + exit 1 + fi diff --git a/.github/workflows/functional-placement.yaml b/.github/workflows/functional-placement.yaml index 9345989800..6897d549f1 100644 --- a/.github/workflows/functional-placement.yaml +++ b/.github/workflows/functional-placement.yaml @@ -2,16 +2,6 @@ name: functional-placement on: merge_group: pull_request: - paths: - - 'openstack/auth_env.go' - - 'openstack/client.go' - - 'openstack/endpoint.go' - - 'openstack/endpoint_location.go' - - 'openstack/config/provider_client.go' - - 'openstack/utils/choose_version.go' - - 'openstack/utils/discovery.go' - - '**placement**' - - '.github/workflows/functional-placement.yaml' schedule: - cron: '0 0 */3 * *' jobs: @@ -41,29 +31,69 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v5 + + - name: Check changed files + uses: ./.github/actions/file-filter + id: changed-files + with: + patterns: | + openstack/auth_env.go + openstack/client.go + openstack/endpoint.go + openstack/endpoint_location.go + openstack/config/provider_client.go + openstack/utils/choose_version.go + openstack/utils/discovery.go + **placement** + .github/workflows/functional-placement.yaml + + - name: Skip tests for unrelated changed-files + if: ${{ ! fromJSON(steps.changed-files.outputs.matches) }} + run: | + echo "No relevant files changed - skipping tests for ${{ matrix.name }}" + echo "TESTS_SKIPPED=true" >> $GITHUB_ENV + - name: Deploy devstack + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: branch: ${{ matrix.openstack_version }} enabled_services: "${{ matrix.additional_services }}" + - name: Checkout go + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: actions/setup-go@v5 with: go-version-file: 'go.mod' cache: true + - name: Run Gophercloud acceptance tests + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} run: | source ${{ github.workspace }}/script/stackenv make acceptance-placement + echo "TESTS_RUN=true" >> $GITHUB_ENV env: DEVSTACK_PATH: ${{ github.workspace }}/devstack OS_BRANCH: ${{ matrix.openstack_version }} + - name: Generate logs on failure run: ./script/collectlogs - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} + - name: Upload logs artifacts on failure - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} uses: actions/upload-artifact@v4 with: name: functional-placement-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* + + - name: Set job status + run: | + if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + echo "Job completed successfully (either ran tests or skipped appropriately)" + exit 0 + else + echo "Job failed - neither tests ran nor were properly skipped" + exit 1 + fi diff --git a/.github/workflows/functional-sharedfilesystems.yaml b/.github/workflows/functional-sharedfilesystems.yaml index 79bb42844d..6cd3958ce1 100644 --- a/.github/workflows/functional-sharedfilesystems.yaml +++ b/.github/workflows/functional-sharedfilesystems.yaml @@ -2,16 +2,6 @@ name: functional-sharedfilesystems on: merge_group: pull_request: - paths: - - 'openstack/auth_env.go' - - 'openstack/client.go' - - 'openstack/endpoint.go' - - 'openstack/endpoint_location.go' - - 'openstack/config/provider_client.go' - - 'openstack/utils/choose_version.go' - - 'openstack/utils/discovery.go' - - '**sharedfilesystems**' - - '.github/workflows/functional-sharedfilesystems.yaml' schedule: - cron: '0 0 */3 * *' jobs: @@ -47,7 +37,30 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v5 + + - name: Check changed files + uses: ./.github/actions/file-filter + id: changed-files + with: + patterns: | + openstack/auth_env.go + openstack/client.go + openstack/endpoint.go + openstack/endpoint_location.go + openstack/config/provider_client.go + openstack/utils/choose_version.go + openstack/utils/discovery.go + **sharedfilesystems** + .github/workflows/functional-sharedfilesystems.yaml + + - name: Skip tests for unrelated changed-files + if: ${{ ! fromJSON(steps.changed-files.outputs.matches) }} + run: | + echo "No relevant files changed - skipping tests for ${{ matrix.name }}" + echo "TESTS_SKIPPED=true" >> $GITHUB_ENV + - name: Deploy devstack + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: branch: ${{ matrix.openstack_version }} @@ -70,24 +83,41 @@ jobs: ${{ matrix.devstack_conf_overrides }} enabled_services: "${{ matrix.additional_services }}" + - name: Checkout go + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: actions/setup-go@v5 with: go-version-file: 'go.mod' cache: true + - name: Run Gophercloud acceptance tests + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} run: | source ${{ github.workspace }}/script/stackenv make acceptance-sharedfilesystems + echo "TESTS_RUN=true" >> $GITHUB_ENV env: DEVSTACK_PATH: ${{ github.workspace }}/devstack OS_BRANCH: ${{ matrix.openstack_version }} + - name: Generate logs on failure run: ./script/collectlogs - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} + - name: Upload logs artifacts on failure - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} uses: actions/upload-artifact@v4 with: name: functional-sharedfilesystems-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* + + - name: Set job status + run: | + if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + echo "Job completed successfully (either ran tests or skipped appropriately)" + exit 0 + else + echo "Job failed - neither tests ran nor were properly skipped" + exit 1 + fi diff --git a/.github/workflows/functional-workflow.yaml b/.github/workflows/functional-workflow.yaml index 2288e90e70..13538ff410 100644 --- a/.github/workflows/functional-workflow.yaml +++ b/.github/workflows/functional-workflow.yaml @@ -2,16 +2,6 @@ name: functional-workflow on: merge_group: pull_request: - paths: - - 'openstack/auth_env.go' - - 'openstack/client.go' - - 'openstack/endpoint.go' - - 'openstack/endpoint_location.go' - - 'openstack/config/provider_client.go' - - 'openstack/utils/choose_version.go' - - 'openstack/utils/discovery.go' - - '**workflow**' - - '.github/workflows/functional-workflow.yaml' schedule: - cron: '0 0 */3 * *' jobs: @@ -45,31 +35,71 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v5 + + - name: Check changed files + uses: ./.github/actions/file-filter + id: changed-files + with: + patterns: | + openstack/auth_env.go + openstack/client.go + openstack/endpoint.go + openstack/endpoint_location.go + openstack/config/provider_client.go + openstack/utils/choose_version.go + openstack/utils/discovery.go + **workflow** + .github/workflows/functional-workflow.yaml + + - name: Skip tests for unrelated changed-files + if: ${{ ! fromJSON(steps.changed-files.outputs.matches) }} + run: | + echo "No relevant files changed - skipping tests for ${{ matrix.name }}" + echo "TESTS_SKIPPED=true" >> $GITHUB_ENV + - name: Deploy devstack + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: branch: ${{ matrix.openstack_version }} conf_overrides: | enable_plugin mistral https://github.com/openstack/mistral ${{ matrix.mistral_plugin_version }} enabled_services: "mistral,mistral-api,mistral-engine,mistral-executor,mistral-event-engine,${{ matrix.additional_services }}" + - name: Checkout go + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: actions/setup-go@v5 with: go-version-file: 'go.mod' cache: true + - name: Run Gophercloud acceptance tests + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} run: | source ${{ github.workspace }}/script/stackenv make acceptance-workflow + echo "TESTS_RUN=true" >> $GITHUB_ENV env: DEVSTACK_PATH: ${{ github.workspace }}/devstack OS_BRANCH: ${{ matrix.openstack_version }} + - name: Generate logs on failure run: ./script/collectlogs - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} + - name: Upload logs artifacts on failure - if: failure() + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} uses: actions/upload-artifact@v4 with: name: functional-workflow-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* + + - name: Set job status + run: | + if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + echo "Job completed successfully (either ran tests or skipped appropriately)" + exit 0 + else + echo "Job failed - neither tests ran nor were properly skipped" + exit 1 + fi From 9d2ef73566073189b953c952cb859c6bd55c7372 Mon Sep 17 00:00:00 2001 From: Sharpz7 Date: Wed, 3 Sep 2025 03:39:29 +0000 Subject: [PATCH 246/429] Initial Commit --- .github/workflows/functional-baremetal.yaml | 4 ++-- .../acceptance/openstack/baremetal/noauth/portgroups_test.go | 3 ++- internal/acceptance/openstack/baremetal/v1/nodes_test.go | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/functional-baremetal.yaml b/.github/workflows/functional-baremetal.yaml index ae0e40333f..e95234847e 100644 --- a/.github/workflows/functional-baremetal.yaml +++ b/.github/workflows/functional-baremetal.yaml @@ -25,7 +25,7 @@ jobs: additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" - ubuntu_version: "22.04" + ubuntu_version: "24.04" additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" @@ -63,7 +63,7 @@ jobs: GLANCE_LIMIT_IMAGE_SIZE_TOTAL=5000 Q_USE_SECGROUP=False API_WORKERS=1 - IRONIC_BAREMETAL_BASIC_OPS=True + IRONIC_BAREMETAL_BASIC_OPS=False IRONIC_BUILD_DEPLOY_RAMDISK=False IRONIC_AUTOMATED_CLEAN_ENABLED=False IRONIC_CALLBACK_TIMEOUT=600 diff --git a/internal/acceptance/openstack/baremetal/noauth/portgroups_test.go b/internal/acceptance/openstack/baremetal/noauth/portgroups_test.go index c3ed33cd67..0ea05ed518 100644 --- a/internal/acceptance/openstack/baremetal/noauth/portgroups_test.go +++ b/internal/acceptance/openstack/baremetal/noauth/portgroups_test.go @@ -15,8 +15,9 @@ import ( func TestPortGroupsCreateDestroy(t *testing.T) { clients.RequireLong(t) + RequireIronicNoAuth(t) - client, err := clients.NewBareMetalV1Client() + client, err := clients.NewBareMetalV1NoAuthClient() th.AssertNoErr(t, err) // NOTE(sharpz7) - increased due to create fake node requiring it. diff --git a/internal/acceptance/openstack/baremetal/v1/nodes_test.go b/internal/acceptance/openstack/baremetal/v1/nodes_test.go index be48ee9197..87030a72e7 100644 --- a/internal/acceptance/openstack/baremetal/v1/nodes_test.go +++ b/internal/acceptance/openstack/baremetal/v1/nodes_test.go @@ -214,7 +214,7 @@ func TestNodesFirmwareInterface(t *testing.T) { } func TestNodesVirtualMedia(t *testing.T) { - clients.SkipReleasesBelow(t, "master") // 2024.1 + clients.SkipReleasesBelow(t, "stable/2024.2") clients.RequireLong(t) client, err := clients.NewBareMetalV1Client() From ec017aefdb8ff99c331cf93e836a0be218d1b124 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Tue, 16 Sep 2025 13:47:35 +0100 Subject: [PATCH 247/429] Trigger "hold" workflow on merge groups Things are currently timing out due to this being missing. Signed-off-by: Stephen Finucane --- .github/workflows/check-pr-labels.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/check-pr-labels.yaml b/.github/workflows/check-pr-labels.yaml index 4fbb7fc0b8..8d3cdde07b 100644 --- a/.github/workflows/check-pr-labels.yaml +++ b/.github/workflows/check-pr-labels.yaml @@ -1,5 +1,6 @@ name: Ready on: + merge_group: pull_request_target: types: - labeled From 6e9876786d0f6f876f0edfd465cd5e8785bf0a01 Mon Sep 17 00:00:00 2001 From: dlawton Date: Wed, 17 Sep 2025 11:55:23 +0100 Subject: [PATCH 248/429] Closes #2321 - Fix TestRolesCRUD by including DomainID to CreateOpts/ListOps structs. Signed-off-by: Dan Lawton --- internal/acceptance/openstack/identity/v3/roles_test.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/internal/acceptance/openstack/identity/v3/roles_test.go b/internal/acceptance/openstack/identity/v3/roles_test.go index ec69a9ba4e..b17ecd9049 100644 --- a/internal/acceptance/openstack/identity/v3/roles_test.go +++ b/internal/acceptance/openstack/identity/v3/roles_test.go @@ -58,7 +58,8 @@ func TestRolesCRUD(t *testing.T) { th.AssertNoErr(t, err) createOpts := roles.CreateOpts{ - Name: "testrole", + Name: "testrole", + DomainID: "default", Extra: map[string]any{ "description": "test role description", }, @@ -72,7 +73,9 @@ func TestRolesCRUD(t *testing.T) { tools.PrintResource(t, role) tools.PrintResource(t, role.Extra) - listOpts := roles.ListOpts{} + listOpts := roles.ListOpts{ + DomainID: "default", + } allPages, err := roles.List(client, listOpts).AllPages(context.TODO()) th.AssertNoErr(t, err) From 04310b14eaea6d657b3c0f8b189300a454e66f01 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Sep 2025 14:18:07 +0000 Subject: [PATCH 249/429] build(deps): bump golang.org/x/crypto from 0.41.0 to 0.42.0 Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.41.0 to 0.42.0. - [Commits](https://github.com/golang/crypto/compare/v0.41.0...v0.42.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-version: 0.42.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 8 +++----- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index 9b62787571..57fd884f66 100644 --- a/go.mod +++ b/go.mod @@ -1,12 +1,10 @@ module github.com/gophercloud/gophercloud/v2 -go 1.23.0 - -toolchain go1.23.6 +go 1.24.0 require ( - golang.org/x/crypto v0.41.0 + golang.org/x/crypto v0.42.0 gopkg.in/yaml.v2 v2.4.0 ) -require golang.org/x/sys v0.35.0 // indirect +require golang.org/x/sys v0.36.0 // indirect diff --git a/go.sum b/go.sum index f1687a61ee..ee0ae6bec7 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ -golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= -golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= -golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= -golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= -golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= +golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= +golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= +golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= +golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= From 38b64e2568c3acbe24770e62982f760009638c47 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Sep 2025 14:18:27 +0000 Subject: [PATCH 250/429] build(deps): bump kiegroup/git-backporting from 4.8.5 to 4.8.6 Bumps [kiegroup/git-backporting](https://github.com/kiegroup/git-backporting) from 4.8.5 to 4.8.6. - [Release notes](https://github.com/kiegroup/git-backporting/releases) - [Changelog](https://github.com/kiegroup/git-backporting/blob/main/CHANGELOG.md) - [Commits](https://github.com/kiegroup/git-backporting/compare/7ff4fce545cf2b9170c91c032bf66a9348ba2490...7d895d030f5cf02f4a76c7f0bc79b41d8747b17c) --- updated-dependencies: - dependency-name: kiegroup/git-backporting dependency-version: 4.8.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/backport.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/backport.yaml b/.github/workflows/backport.yaml index 00e787285f..86504701ea 100644 --- a/.github/workflows/backport.yaml +++ b/.github/workflows/backport.yaml @@ -34,7 +34,7 @@ jobs: if: > contains(github.event.pull_request.labels.*.name, 'semver:patch') || contains(github.event.label.name, 'semver:patch') - uses: kiegroup/git-backporting@7ff4fce545cf2b9170c91c032bf66a9348ba2490 + uses: kiegroup/git-backporting@7d895d030f5cf02f4a76c7f0bc79b41d8747b17c with: target-branch: v1 pull-request: ${{ github.event.pull_request.url }} @@ -97,7 +97,7 @@ jobs: || contains(github.event.pull_request.labels.*.name, 'semver:minor') || contains(github.event.label.name, 'semver:patch') || contains(github.event.label.name, 'semver:minor') - uses: kiegroup/git-backporting@7ff4fce545cf2b9170c91c032bf66a9348ba2490 + uses: kiegroup/git-backporting@7d895d030f5cf02f4a76c7f0bc79b41d8747b17c with: target-branch: v2 pull-request: ${{ github.event.pull_request.url }} From 50cc13cc4e16020dfaf14b2474aaeacefffd28c6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Sep 2025 14:18:29 +0000 Subject: [PATCH 251/429] build(deps): bump actions/labeler from 5 to 6 Bumps [actions/labeler](https://github.com/actions/labeler) from 5 to 6. - [Release notes](https://github.com/actions/labeler/releases) - [Commits](https://github.com/actions/labeler/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/labeler dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/label-pr.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/label-pr.yaml b/.github/workflows/label-pr.yaml index 15abc3203c..578694dc72 100644 --- a/.github/workflows/label-pr.yaml +++ b/.github/workflows/label-pr.yaml @@ -84,4 +84,4 @@ jobs: pull-requests: write runs-on: ubuntu-latest steps: - - uses: actions/labeler@v5 + - uses: actions/labeler@v6 From 2ab97519c65cf5612ceddf118258cd45d4de2f1f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Sep 2025 14:18:53 +0000 Subject: [PATCH 252/429] build(deps): bump actions/setup-go from 5 to 6 Bumps [actions/setup-go](https://github.com/actions/setup-go) from 5 to 6. - [Release notes](https://github.com/actions/setup-go/releases) - [Commits](https://github.com/actions/setup-go/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/setup-go dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql-analysis.yaml | 2 +- .github/workflows/functional-baremetal.yaml | 2 +- .github/workflows/functional-basic.yaml | 2 +- .github/workflows/functional-blockstorage.yaml | 2 +- .github/workflows/functional-compute.yaml | 2 +- .github/workflows/functional-containerinfra.yaml | 2 +- .github/workflows/functional-dns.yaml | 2 +- .github/workflows/functional-fwaas_v2.yaml | 2 +- .github/workflows/functional-identity.yaml | 2 +- .github/workflows/functional-image.yaml | 2 +- .github/workflows/functional-keymanager.yaml | 2 +- .github/workflows/functional-loadbalancer.yaml | 2 +- .github/workflows/functional-messaging.yaml | 2 +- .github/workflows/functional-networking.yaml | 2 +- .github/workflows/functional-objectstorage.yaml | 2 +- .github/workflows/functional-orchestration.yaml | 2 +- .github/workflows/functional-placement.yaml | 2 +- .github/workflows/functional-sharedfilesystems.yaml | 2 +- .github/workflows/functional-workflow.yaml | 2 +- .github/workflows/label-pr.yaml | 2 +- .github/workflows/lint.yaml | 2 +- .github/workflows/unit.yaml | 2 +- 22 files changed, 22 insertions(+), 22 deletions(-) diff --git a/.github/workflows/codeql-analysis.yaml b/.github/workflows/codeql-analysis.yaml index 58952951c6..b24893a9e5 100644 --- a/.github/workflows/codeql-analysis.yaml +++ b/.github/workflows/codeql-analysis.yaml @@ -21,7 +21,7 @@ jobs: uses: actions/checkout@v5 - name: Setup Go - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-baremetal.yaml b/.github/workflows/functional-baremetal.yaml index f850bd11ab..1fe5fadf50 100644 --- a/.github/workflows/functional-baremetal.yaml +++ b/.github/workflows/functional-baremetal.yaml @@ -100,7 +100,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-basic.yaml b/.github/workflows/functional-basic.yaml index 756c742cc2..70acbf3762 100644 --- a/.github/workflows/functional-basic.yaml +++ b/.github/workflows/functional-basic.yaml @@ -58,7 +58,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-blockstorage.yaml b/.github/workflows/functional-blockstorage.yaml index 7c4ab14bac..86f7de3671 100644 --- a/.github/workflows/functional-blockstorage.yaml +++ b/.github/workflows/functional-blockstorage.yaml @@ -64,7 +64,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-compute.yaml b/.github/workflows/functional-compute.yaml index 8d932e44b5..5322a86401 100644 --- a/.github/workflows/functional-compute.yaml +++ b/.github/workflows/functional-compute.yaml @@ -64,7 +64,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-containerinfra.yaml b/.github/workflows/functional-containerinfra.yaml index bca3ee49b0..6172dccb03 100644 --- a/.github/workflows/functional-containerinfra.yaml +++ b/.github/workflows/functional-containerinfra.yaml @@ -94,7 +94,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-dns.yaml b/.github/workflows/functional-dns.yaml index 51adcd0535..ee57512203 100644 --- a/.github/workflows/functional-dns.yaml +++ b/.github/workflows/functional-dns.yaml @@ -72,7 +72,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-fwaas_v2.yaml b/.github/workflows/functional-fwaas_v2.yaml index 3fd3e971eb..5e2cadc271 100644 --- a/.github/workflows/functional-fwaas_v2.yaml +++ b/.github/workflows/functional-fwaas_v2.yaml @@ -87,7 +87,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-identity.yaml b/.github/workflows/functional-identity.yaml index f1c920981b..37622af366 100644 --- a/.github/workflows/functional-identity.yaml +++ b/.github/workflows/functional-identity.yaml @@ -62,7 +62,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-image.yaml b/.github/workflows/functional-image.yaml index eb299c93b3..c05fad1e80 100644 --- a/.github/workflows/functional-image.yaml +++ b/.github/workflows/functional-image.yaml @@ -62,7 +62,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-keymanager.yaml b/.github/workflows/functional-keymanager.yaml index b5db25d8ca..44d9607067 100644 --- a/.github/workflows/functional-keymanager.yaml +++ b/.github/workflows/functional-keymanager.yaml @@ -78,7 +78,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-loadbalancer.yaml b/.github/workflows/functional-loadbalancer.yaml index 02df282845..3f73436037 100644 --- a/.github/workflows/functional-loadbalancer.yaml +++ b/.github/workflows/functional-loadbalancer.yaml @@ -73,7 +73,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-messaging.yaml b/.github/workflows/functional-messaging.yaml index 7f8ef7cc8e..0222956e89 100644 --- a/.github/workflows/functional-messaging.yaml +++ b/.github/workflows/functional-messaging.yaml @@ -65,7 +65,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-networking.yaml b/.github/workflows/functional-networking.yaml index 4ae22544f0..28107f4fc5 100644 --- a/.github/workflows/functional-networking.yaml +++ b/.github/workflows/functional-networking.yaml @@ -82,7 +82,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-objectstorage.yaml b/.github/workflows/functional-objectstorage.yaml index 38d37a793e..fb71022fba 100644 --- a/.github/workflows/functional-objectstorage.yaml +++ b/.github/workflows/functional-objectstorage.yaml @@ -68,7 +68,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-orchestration.yaml b/.github/workflows/functional-orchestration.yaml index 4322089751..45859d2fac 100644 --- a/.github/workflows/functional-orchestration.yaml +++ b/.github/workflows/functional-orchestration.yaml @@ -64,7 +64,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-placement.yaml b/.github/workflows/functional-placement.yaml index 6897d549f1..2219c99a0a 100644 --- a/.github/workflows/functional-placement.yaml +++ b/.github/workflows/functional-placement.yaml @@ -62,7 +62,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-sharedfilesystems.yaml b/.github/workflows/functional-sharedfilesystems.yaml index 6cd3958ce1..cac6da18da 100644 --- a/.github/workflows/functional-sharedfilesystems.yaml +++ b/.github/workflows/functional-sharedfilesystems.yaml @@ -86,7 +86,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-workflow.yaml b/.github/workflows/functional-workflow.yaml index 13538ff410..4ac0dde74d 100644 --- a/.github/workflows/functional-workflow.yaml +++ b/.github/workflows/functional-workflow.yaml @@ -68,7 +68,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/label-pr.yaml b/.github/workflows/label-pr.yaml index 15abc3203c..e9955df9b8 100644 --- a/.github/workflows/label-pr.yaml +++ b/.github/workflows/label-pr.yaml @@ -24,7 +24,7 @@ jobs: env: GIT_SEQUENCE_EDITOR: '/usr/bin/true' - - uses: actions/setup-go@v5 + - uses: actions/setup-go@v6 with: go-version: '1' diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index f1696959e9..9c2d4787fa 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -11,7 +11,7 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v5 - - uses: actions/setup-go@v5 + - uses: actions/setup-go@v6 with: go-version: '1' - name: Run linters diff --git a/.github/workflows/unit.yaml b/.github/workflows/unit.yaml index ee7eb7fd58..4cda470c05 100644 --- a/.github/workflows/unit.yaml +++ b/.github/workflows/unit.yaml @@ -17,7 +17,7 @@ jobs: - name: Checkout Gophercloud uses: actions/checkout@v5 - name: Setup Go - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version-file: 'go.mod' cache: true From caa35e72707ea098b40ca0e9ecd4ea1e99912754 Mon Sep 17 00:00:00 2001 From: Sharpz7 Date: Wed, 17 Sep 2025 19:17:51 +0000 Subject: [PATCH 253/429] Added comment addressing IRONIC_BAREMETAL_BASIC_OPS=false --- .github/workflows/functional-baremetal.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/functional-baremetal.yaml b/.github/workflows/functional-baremetal.yaml index 1fe5fadf50..c4c9929f6d 100644 --- a/.github/workflows/functional-baremetal.yaml +++ b/.github/workflows/functional-baremetal.yaml @@ -57,6 +57,9 @@ jobs: if: ${{ fromJSON(steps.changed-files.outputs.matches) }} run: sudo apt-get purge -y dnsmasq-base + # NOTE(sharpz7) IRONIC_BAREMETAL_BASIC_OPS was originally set to false as it + # was failing (https://review.opendev.org/c/openstack/ironic/+/960299) + # See https://github.com/gophercloud/gophercloud/pull/3500 - name: Deploy devstack if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 From 816179ee8a7c0722341c8213ba7e53dd937e97e7 Mon Sep 17 00:00:00 2001 From: Sharpz7 Date: Wed, 17 Sep 2025 19:38:19 +0000 Subject: [PATCH 254/429] Changed wording --- .github/workflows/functional-baremetal.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/functional-baremetal.yaml b/.github/workflows/functional-baremetal.yaml index c4c9929f6d..341060fbb0 100644 --- a/.github/workflows/functional-baremetal.yaml +++ b/.github/workflows/functional-baremetal.yaml @@ -60,6 +60,7 @@ jobs: # NOTE(sharpz7) IRONIC_BAREMETAL_BASIC_OPS was originally set to false as it # was failing (https://review.opendev.org/c/openstack/ironic/+/960299) # See https://github.com/gophercloud/gophercloud/pull/3500 + # This change however is suitable longer-term as it is not necessary for SDK testing. - name: Deploy devstack if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 From 8397c0eaf24b36ee4a0fbb40ec968407e36b94d8 Mon Sep 17 00:00:00 2001 From: Pierre Prinetti Date: Sun, 21 Sep 2025 15:47:09 +0200 Subject: [PATCH 255/429] refactor: Trivial fixes Address some gopls suggestions. The behaviour of the code is expected to remain unchanged. --- pagination/testing/doc.go | 2 -- provider_client.go | 13 +++---------- util.go | 3 --- 3 files changed, 3 insertions(+), 15 deletions(-) delete mode 100644 pagination/testing/doc.go diff --git a/pagination/testing/doc.go b/pagination/testing/doc.go deleted file mode 100644 index 0bc1eb3807..0000000000 --- a/pagination/testing/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// pagination -package testing diff --git a/provider_client.go b/provider_client.go index 598596c61e..a75592a2d1 100644 --- a/provider_client.go +++ b/provider_client.go @@ -7,6 +7,7 @@ import ( "errors" "io" "net/http" + "slices" "strings" "sync" ) @@ -437,16 +438,8 @@ func (client *ProviderClient) doRequest(ctx context.Context, method, url string, okc = defaultOkCodes(method) } - // Validate the HTTP response status. - var ok bool - for _, code := range okc { - if resp.StatusCode == code { - ok = true - break - } - } - - if !ok { + // Check the response code against the acceptable codes + if !slices.Contains(okc, resp.StatusCode) { body, _ := io.ReadAll(resp.Body) resp.Body.Close() respErr := ErrUnexpectedResponseCode{ diff --git a/util.go b/util.go index ad8a7dfaaa..d11a723b1b 100644 --- a/util.go +++ b/util.go @@ -37,9 +37,6 @@ func NormalizePathURL(basePath, rawPath string) (string, error) { absPathSys = filepath.Join(basePath, rawPath) u.Path = filepath.ToSlash(absPathSys) - if err != nil { - return "", err - } u.Scheme = "file" return u.String(), nil } From 80936c08a751cea1b551f160680e82e08b6fb4b4 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Wed, 24 Sep 2025 16:34:28 +0100 Subject: [PATCH 256/429] Bump golangci-lint, gotestsum Signed-off-by: Stephen Finucane --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 2d9cc5939b..e5b77e0369 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ undefine GOFLAGS -GOLANGCI_LINT_VERSION?=v2.1.6 -GOTESTSUM_VERSION?=v1.12.2 +GOLANGCI_LINT_VERSION?=v2.5.0 +GOTESTSUM_VERSION?=v1.13.0 GO_TEST?=go run gotest.tools/gotestsum@$(GOTESTSUM_VERSION) --format testname -- TIMEOUT := "60m" From b23a891a4d00f5a7a19be0709dc164e41180eac3 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Fri, 26 Sep 2025 13:10:10 +0100 Subject: [PATCH 257/429] compute: Add host aggregate uuid field Signed-off-by: Stephen Finucane --- openstack/compute/v2/aggregates/results.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openstack/compute/v2/aggregates/results.go b/openstack/compute/v2/aggregates/results.go index 0d4794acff..8e67edd87c 100644 --- a/openstack/compute/v2/aggregates/results.go +++ b/openstack/compute/v2/aggregates/results.go @@ -39,6 +39,10 @@ type Aggregate struct { // A boolean indicates whether this aggregate is deleted or not, // if it has not been deleted, false will appear. Deleted bool `json:"deleted"` + + // The UUID of the aggregate. + // The requires microversion 2.41 or later. + UUID string `json:"uuid"` } // UnmarshalJSON to override default From bba1cb59c99a01e8a2ab98a6c7e7aa43fc275d3a Mon Sep 17 00:00:00 2001 From: Bram Kranendonk Date: Sat, 27 Sep 2025 13:19:35 +0200 Subject: [PATCH 258/429] Add image uploading status --- openstack/image/v2/images/types.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openstack/image/v2/images/types.go b/openstack/image/v2/images/types.go index 147be19927..eedc13a330 100644 --- a/openstack/image/v2/images/types.go +++ b/openstack/image/v2/images/types.go @@ -13,10 +13,14 @@ const ( // been reserved for an image in the image registry. ImageStatusQueued ImageStatus = "queued" - // ImageStatusSaving denotes that an image’s raw data is currently being + // ImageStatusSaving denotes that an image's raw data is currently being // uploaded to Glance ImageStatusSaving ImageStatus = "saving" + // ImageStatusUploading denotes that an image's raw data is currently being + // uploaded to Glance through the upload process + ImageStatusUploading ImageStatus = "uploading" + // ImageStatusActive denotes an image that is fully available in Glance. ImageStatusActive ImageStatus = "active" From 81eb442beecea50c0a41c3fb21ba5f7ec5712bdf Mon Sep 17 00:00:00 2001 From: Maximilian Meister Date: Wed, 24 Sep 2025 08:47:57 +0200 Subject: [PATCH 259/429] Enable load balancer quota deletion --- .../openstack/loadbalancer/v2/quotas_test.go | 10 ++++++++++ openstack/loadbalancer/v2/quotas/doc.go | 10 ++++++++++ openstack/loadbalancer/v2/quotas/requests.go | 6 ++++++ openstack/loadbalancer/v2/quotas/results.go | 6 ++++++ .../v2/quotas/testing/fixtures_test.go | 18 +++++++++++++++++- .../v2/quotas/testing/requests_test.go | 10 ++++++++++ openstack/loadbalancer/v2/quotas/urls.go | 4 ++++ 7 files changed, 63 insertions(+), 1 deletion(-) diff --git a/internal/acceptance/openstack/loadbalancer/v2/quotas_test.go b/internal/acceptance/openstack/loadbalancer/v2/quotas_test.go index cc778e5403..87f9d7621f 100644 --- a/internal/acceptance/openstack/loadbalancer/v2/quotas_test.go +++ b/internal/acceptance/openstack/loadbalancer/v2/quotas_test.go @@ -80,3 +80,13 @@ func TestQuotasUpdate(t *testing.T) { tools.PrintResource(t, restoredQuotas) } + +func TestQuotasDelete(t *testing.T) { + clients.RequireAdmin(t) + + client, err := clients.NewLoadBalancerV2Client() + th.AssertNoErr(t, err) + + err = quotas.Delete(context.TODO(), client, os.Getenv("OS_PROJECT_NAME")).ExtractErr() + th.AssertNoErr(t, err) +} diff --git a/openstack/loadbalancer/v2/quotas/doc.go b/openstack/loadbalancer/v2/quotas/doc.go index c2c63512c3..77c5600226 100644 --- a/openstack/loadbalancer/v2/quotas/doc.go +++ b/openstack/loadbalancer/v2/quotas/doc.go @@ -30,5 +30,15 @@ Example to Update project quotas } fmt.Printf("quotas: %#v\n", quotasInfo) + +Example to Delete project quotas + + projectID = "23d5d3f79dfa4f73b72b8b0b0063ec55" + err := quotas.Delete(context.TODO(), networkClient, projectID).ExtractErr() + if err != nil { + log.Fatal(err) + } + + fmt.Printf("Deleted quotas for project: %s\n", projectID) */ package quotas diff --git a/openstack/loadbalancer/v2/quotas/requests.go b/openstack/loadbalancer/v2/quotas/requests.go index 8b7771eea8..f07f9392e9 100644 --- a/openstack/loadbalancer/v2/quotas/requests.go +++ b/openstack/loadbalancer/v2/quotas/requests.go @@ -63,3 +63,9 @@ func Update(ctx context.Context, c *gophercloud.ServiceClient, projectID string, _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return } + +func Delete(ctx context.Context, c *gophercloud.ServiceClient, projectID string) (r DeleteResult) { + resp, err := c.Delete(ctx, deleteURL(c, projectID), nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} diff --git a/openstack/loadbalancer/v2/quotas/results.go b/openstack/loadbalancer/v2/quotas/results.go index e1ef385982..5487d7a84e 100644 --- a/openstack/loadbalancer/v2/quotas/results.go +++ b/openstack/loadbalancer/v2/quotas/results.go @@ -96,3 +96,9 @@ func (r *Quota) UnmarshalJSON(b []byte) error { return nil } + +// DeleteResult is the response from a Delete operation. Call its ExtractErr +// method to determine if the request succeeded or failed. +type DeleteResult struct { + gophercloud.ErrResult +} diff --git a/openstack/loadbalancer/v2/quotas/testing/fixtures_test.go b/openstack/loadbalancer/v2/quotas/testing/fixtures_test.go index e5185b2012..e4609aa868 100644 --- a/openstack/loadbalancer/v2/quotas/testing/fixtures_test.go +++ b/openstack/loadbalancer/v2/quotas/testing/fixtures_test.go @@ -1,6 +1,13 @@ package testing -import "github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/quotas" +import ( + "net/http" + "testing" + + "github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/quotas" + fake "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/common" + th "github.com/gophercloud/gophercloud/v2/testhelper" +) const GetResponseRaw_1 = ` { @@ -77,3 +84,12 @@ var UpdateResponse = quotas.Quota{ L7Policy: 50, L7Rule: 100, } + +func MockDeleteResponse(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/v2.0/quotas/0a73845280574ad389c292f6a74afa76", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "DELETE") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + + w.WriteHeader(http.StatusNoContent) + }) +} diff --git a/openstack/loadbalancer/v2/quotas/testing/requests_test.go b/openstack/loadbalancer/v2/quotas/testing/requests_test.go index ccf8e51f35..ab3ba6a177 100644 --- a/openstack/loadbalancer/v2/quotas/testing/requests_test.go +++ b/openstack/loadbalancer/v2/quotas/testing/requests_test.go @@ -105,3 +105,13 @@ func TestUpdate_2(t *testing.T) { th.AssertNoErr(t, err) th.AssertDeepEquals(t, q, &UpdateResponse) } + +func TestDelete(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + MockDeleteResponse(t, fakeServer) + + res := quotas.Delete(context.TODO(), fake.ServiceClient(fakeServer), "0a73845280574ad389c292f6a74afa76") + th.AssertNoErr(t, res.Err) +} diff --git a/openstack/loadbalancer/v2/quotas/urls.go b/openstack/loadbalancer/v2/quotas/urls.go index 0365d9c8ad..545e832307 100644 --- a/openstack/loadbalancer/v2/quotas/urls.go +++ b/openstack/loadbalancer/v2/quotas/urls.go @@ -15,3 +15,7 @@ func getURL(c *gophercloud.ServiceClient, projectID string) string { func updateURL(c *gophercloud.ServiceClient, projectID string) string { return resourceURL(c, projectID) } + +func deleteURL(c *gophercloud.ServiceClient, projectID string) string { + return getURL(c, projectID) +} From 1abcebd1252541ce49fe6a5bb2c1a6cebf6f7ed6 Mon Sep 17 00:00:00 2001 From: Maximilian Meister Date: Wed, 24 Sep 2025 09:34:08 +0200 Subject: [PATCH 260/429] Enable network quota deletion --- .../networking/v2/extensions/quotas/quotas_test.go | 10 ++++++++++ openstack/networking/v2/extensions/quotas/doc.go | 10 ++++++++++ .../networking/v2/extensions/quotas/requests.go | 6 ++++++ .../networking/v2/extensions/quotas/results.go | 6 ++++++ .../v2/extensions/quotas/testing/fixtures_test.go | 14 ++++++++++++++ .../v2/extensions/quotas/testing/requests_test.go | 10 ++++++++++ openstack/networking/v2/extensions/quotas/urls.go | 4 ++++ 7 files changed, 60 insertions(+) diff --git a/internal/acceptance/openstack/networking/v2/extensions/quotas/quotas_test.go b/internal/acceptance/openstack/networking/v2/extensions/quotas/quotas_test.go index 3eaf7d232b..06b2280791 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/quotas/quotas_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/quotas/quotas_test.go @@ -63,3 +63,13 @@ func TestQuotasUpdate(t *testing.T) { tools.PrintResource(t, restoredQuotas) } + +func TestQuotasDelete(t *testing.T) { + clients.RequireAdmin(t) + + client, err := clients.NewNetworkV2Client() + th.AssertNoErr(t, err) + + err = quotas.Delete(context.TODO(), client, os.Getenv("OS_PROJECT_NAME")).ExtractErr() + th.AssertNoErr(t, err) +} diff --git a/openstack/networking/v2/extensions/quotas/doc.go b/openstack/networking/v2/extensions/quotas/doc.go index fe1cc26311..5e5ec3e58a 100644 --- a/openstack/networking/v2/extensions/quotas/doc.go +++ b/openstack/networking/v2/extensions/quotas/doc.go @@ -43,5 +43,15 @@ Example to Update project quotas } fmt.Printf("quotas: %#v\n", quotasInfo) + +Example to Delete project quotas + + projectID = "23d5d3f79dfa4f73b72b8b0b0063ec55" + err := quotas.Delete(context.TODO(), networkClient, projectID).ExtractErr() + if err != nil { + log.Fatal(err) + } + + fmt.Printf("Deleted quotas for project: %s\n", projectID) */ package quotas diff --git a/openstack/networking/v2/extensions/quotas/requests.go b/openstack/networking/v2/extensions/quotas/requests.go index 859c552cef..6289368841 100644 --- a/openstack/networking/v2/extensions/quotas/requests.go +++ b/openstack/networking/v2/extensions/quotas/requests.go @@ -78,3 +78,9 @@ func Update(ctx context.Context, c *gophercloud.ServiceClient, projectID string, _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return } + +func Delete(ctx context.Context, c *gophercloud.ServiceClient, projectID string) (r DeleteResult) { + resp, err := c.Delete(ctx, deleteURL(c, projectID), nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} diff --git a/openstack/networking/v2/extensions/quotas/results.go b/openstack/networking/v2/extensions/quotas/results.go index 249d115175..5fa10cf21d 100644 --- a/openstack/networking/v2/extensions/quotas/results.go +++ b/openstack/networking/v2/extensions/quotas/results.go @@ -171,3 +171,9 @@ func (q *QuotaDetail) UnmarshalJSON(b []byte) error { return nil } + +// DeleteResult is the response from a Delete operation. Call its ExtractErr +// method to determine if the request succeeded or failed. +type DeleteResult struct { + gophercloud.ErrResult +} diff --git a/openstack/networking/v2/extensions/quotas/testing/fixtures_test.go b/openstack/networking/v2/extensions/quotas/testing/fixtures_test.go index a4a7703c89..1f34dead15 100644 --- a/openstack/networking/v2/extensions/quotas/testing/fixtures_test.go +++ b/openstack/networking/v2/extensions/quotas/testing/fixtures_test.go @@ -1,7 +1,12 @@ package testing import ( + "net/http" + "testing" + + fake "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/common" "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/quotas" + th "github.com/gophercloud/gophercloud/v2/testhelper" ) const GetResponseRaw = ` @@ -140,3 +145,12 @@ var UpdateResponse = quotas.Quota{ SubnetPool: 0, Trunk: 5, } + +func MockDeleteResponse(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/v2.0/quotas/0a73845280574ad389c292f6a74afa76", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "DELETE") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + + w.WriteHeader(http.StatusNoContent) + }) +} diff --git a/openstack/networking/v2/extensions/quotas/testing/requests_test.go b/openstack/networking/v2/extensions/quotas/testing/requests_test.go index 597edd4853..e4550c11fd 100644 --- a/openstack/networking/v2/extensions/quotas/testing/requests_test.go +++ b/openstack/networking/v2/extensions/quotas/testing/requests_test.go @@ -80,3 +80,13 @@ func TestUpdate(t *testing.T) { th.AssertNoErr(t, err) th.AssertDeepEquals(t, q, &UpdateResponse) } + +func TestDelete(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + MockDeleteResponse(t, fakeServer) + + res := quotas.Delete(context.TODO(), fake.ServiceClient(fakeServer), "0a73845280574ad389c292f6a74afa76") + th.AssertNoErr(t, res.Err) +} diff --git a/openstack/networking/v2/extensions/quotas/urls.go b/openstack/networking/v2/extensions/quotas/urls.go index 94cbe23880..726c4da8eb 100644 --- a/openstack/networking/v2/extensions/quotas/urls.go +++ b/openstack/networking/v2/extensions/quotas/urls.go @@ -24,3 +24,7 @@ func getDetailURL(c *gophercloud.ServiceClient, projectID string) string { func updateURL(c *gophercloud.ServiceClient, projectID string) string { return resourceURL(c, projectID) } + +func deleteURL(c *gophercloud.ServiceClient, projectID string) string { + return getURL(c, projectID) +} From a108557f9118bab942a45317e2860570931da621 Mon Sep 17 00:00:00 2001 From: Maximilian Meister Date: Wed, 1 Oct 2025 08:08:57 +0200 Subject: [PATCH 261/429] Add acceptance testing hint to contribution docs Also fix broken link --- docs/contributor-tutorial/step-04-acceptance-testing.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/contributor-tutorial/step-04-acceptance-testing.md b/docs/contributor-tutorial/step-04-acceptance-testing.md index fe82717439..a6708ee5fb 100644 --- a/docs/contributor-tutorial/step-04-acceptance-testing.md +++ b/docs/contributor-tutorial/step-04-acceptance-testing.md @@ -17,9 +17,13 @@ And, to be frank, submitting untested code will inevitably cause someone else to have to spend time fixing it. If you don't have an OpenStack environment to test with, we have lots of -documentation [here](/acceptance) to help you build your own small OpenStack +documentation [here](/internal/acceptance) to help you build your own small OpenStack environment for testing. +If you add new API calls/actions e.g. also make sure to include them into the +respective [acceptance tests](/internal/acceptance/openstack) for the code to be +validated against all the supported OpenStack versions. + --- Once you've confirmed you are able to test your code, proceed to From c210c547b819a392d4b8e05e7d9380d45cf8afb4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 9 Oct 2025 09:13:26 +0000 Subject: [PATCH 262/429] build(deps): bump golang.org/x/crypto from 0.42.0 to 0.43.0 Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.42.0 to 0.43.0. - [Commits](https://github.com/golang/crypto/compare/v0.42.0...v0.43.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-version: 0.43.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 57fd884f66..033b59f3ec 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module github.com/gophercloud/gophercloud/v2 go 1.24.0 require ( - golang.org/x/crypto v0.42.0 + golang.org/x/crypto v0.43.0 gopkg.in/yaml.v2 v2.4.0 ) -require golang.org/x/sys v0.36.0 // indirect +require golang.org/x/sys v0.37.0 // indirect diff --git a/go.sum b/go.sum index ee0ae6bec7..fc73315e9a 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ -golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= -golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= -golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= -golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= -golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= +golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= +golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= +golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= +golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= +golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= From ffb0d11eb2c7059b30c29f5a5b02baa5fa506d6f Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Fri, 24 Oct 2025 13:16:23 +0100 Subject: [PATCH 263/429] docs: Document tested releases for acceptance tests Signed-off-by: Stephen Finucane --- docs/contributor-tutorial/step-05-pull-requests.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/contributor-tutorial/step-05-pull-requests.md b/docs/contributor-tutorial/step-05-pull-requests.md index c65eff8789..5f29a938e4 100644 --- a/docs/contributor-tutorial/step-05-pull-requests.md +++ b/docs/contributor-tutorial/step-05-pull-requests.md @@ -99,7 +99,10 @@ generate your own fixtures using the OpenStack environment you're Since unit tests are not run against an actual OpenStack environment, acceptance tests can arguably be more important. The acceptance tests that you include in your Pull Request should confirm that your implemented code works -as intended with an actual OpenStack environment. +as intended with an actual OpenStack environment. We run our functional jobs +against all supported Skip Level Upgrade Release Process (SLURP) releases as +well as `master`. This information is sourced from +[releases.openstack.org](https://releases.openstack.org/). ### Documentation From 42acda1a102aab46e920f4dd8ba3b11a021e284e Mon Sep 17 00:00:00 2001 From: Local rebase Date: Fri, 24 Oct 2025 12:08:24 +0100 Subject: [PATCH 264/429] Identity: Add Options field to roles. Signed-off-by: Dan Lawton --- .../openstack/identity/v3/roles_test.go | 6 ++ openstack/identity/v3/roles/requests.go | 14 ++++ openstack/identity/v3/roles/results.go | 3 + .../v3/roles/testing/fixtures_test.go | 82 +++++++++++++++++-- .../v3/roles/testing/requests_test.go | 24 ++++++ 5 files changed, 122 insertions(+), 7 deletions(-) diff --git a/internal/acceptance/openstack/identity/v3/roles_test.go b/internal/acceptance/openstack/identity/v3/roles_test.go index b17ecd9049..96337dc4c1 100644 --- a/internal/acceptance/openstack/identity/v3/roles_test.go +++ b/internal/acceptance/openstack/identity/v3/roles_test.go @@ -63,6 +63,9 @@ func TestRolesCRUD(t *testing.T) { Extra: map[string]any{ "description": "test role description", }, + Options: map[roles.Option]any{ + "immutable": false, + }, } // Create Role in the default domain @@ -98,6 +101,9 @@ func TestRolesCRUD(t *testing.T) { Extra: map[string]any{ "description": "updated test role description", }, + Options: map[roles.Option]any{ + "immutable": nil, + }, } newRole, err := roles.Update(context.TODO(), client, role.ID, updateOpts).Extract() diff --git a/openstack/identity/v3/roles/requests.go b/openstack/identity/v3/roles/requests.go index 2e40e93d6d..0552dc2852 100644 --- a/openstack/identity/v3/roles/requests.go +++ b/openstack/identity/v3/roles/requests.go @@ -9,6 +9,14 @@ import ( "github.com/gophercloud/gophercloud/v2/pagination" ) +// Option is a specific option defined at the API to enable features +// on a role. +type Option string + +const ( + Immutable Option = "immutable" +) + // ListOptsBuilder allows extensions to add additional parameters to // the List request type ListOptsBuilder interface { @@ -88,6 +96,9 @@ type CreateOpts struct { // Extra is free-form extra key/value pairs to describe the role. Extra map[string]any `json:"-"` + + // Options are defined options in the API to enable certain features. + Options map[Option]any `json:"options,omitempty"` } // ToRoleCreateMap formats a CreateOpts into a create request. @@ -135,6 +146,9 @@ type UpdateOpts struct { // Extra is free-form extra key/value pairs to describe the role. Extra map[string]any `json:"-"` + + // Options are defined options in the API to enable certain features. + Options map[Option]any `json:"options,omitempty"` } // ToRoleUpdateMap formats a UpdateOpts into an update request. diff --git a/openstack/identity/v3/roles/results.go b/openstack/identity/v3/roles/results.go index 43abaf6477..b2e348df06 100644 --- a/openstack/identity/v3/roles/results.go +++ b/openstack/identity/v3/roles/results.go @@ -23,6 +23,9 @@ type Role struct { // Extra is a collection of miscellaneous key/values. Extra map[string]any `json:"-"` + + // Options are a set of defined options that allow certain features for a role + Options map[Option]any `json:"options"` } func (r *Role) UnmarshalJSON(b []byte) error { diff --git a/openstack/identity/v3/roles/testing/fixtures_test.go b/openstack/identity/v3/roles/testing/fixtures_test.go index 1e8403eb64..3fa6171c1b 100644 --- a/openstack/identity/v3/roles/testing/fixtures_test.go +++ b/openstack/identity/v3/roles/testing/fixtures_test.go @@ -52,9 +52,25 @@ const GetOutput = ` "self": "https://example.com/identity/v3/roles/9fe1d3" }, "name": "support", - "extra": { - "description": "read-only support role" - } + "description": "read-only support role" + } +} +` + +// GetOutputWithOptions provides a Get result of a role with options. +const GetOutputWithOptions = ` +{ + "role": { + "domain_id": "1789d1", + "id": "9fe1d3", + "links": { + "self": "https://example.com/identity/v3/roles/9fe1d3" + }, + "name": "support", + "description": "read-only support role", + "options": { + "immutable": true + } } } ` @@ -65,8 +81,22 @@ const CreateRequest = ` "role": { "domain_id": "1789d1", "name": "support", - "description": "read-only support role" - } + "description": "read-only support role" + } +} +` + +// CreateRequestWithOptions provides the input to a Create request with Options. +const CreateRequestWithOptions = ` +{ + "role": { + "domain_id": "1789d1", + "name": "support", + "description": "read-only support role", + "options": { + "immutable": true + } + } } ` @@ -74,7 +104,10 @@ const CreateRequest = ` const UpdateRequest = ` { "role": { - "description": "admin read-only support role" + "description": "admin read-only support role", + "options": { + "immutable": false + } } } ` @@ -91,7 +124,10 @@ const UpdateOutput = ` "name": "support", "extra": { "description": "admin read-only support role" - } + }, + "options": { + "immutable": false + } } } ` @@ -324,6 +360,22 @@ var SecondRole = roles.Role{ }, } +// SecondRoleWithOptions is the second role in the List request +var SecondRoleWithOptions = roles.Role{ + DomainID: "1789d1", + ID: "9fe1d3", + Links: map[string]any{ + "self": "https://example.com/identity/v3/roles/9fe1d3", + }, + Name: "support", + Extra: map[string]any{ + "description": "read-only support role", + }, + Options: map[roles.Option]any{ + roles.Immutable: true, + }, +} + // SecondRoleUpdated is how SecondRole should look after an Update. var SecondRoleUpdated = roles.Role{ DomainID: "1789d1", @@ -335,6 +387,9 @@ var SecondRoleUpdated = roles.Role{ Extra: map[string]any{ "description": "admin read-only support role", }, + Options: map[roles.Option]any{ + roles.Immutable: false, + }, } // ExpectedRolesSlice is the slice of roles expected to be returned from ListOutput. @@ -381,6 +436,19 @@ func HandleCreateRoleSuccessfully(t *testing.T, fakeServer th.FakeServer) { }) } +// HandleCreateRoleWithOptionsSuccessfully creates an HTTP handler at `/roles` on the +// test handler mux that tests role creation. +func HandleCreateWithOptionsRoleSuccessfully(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/roles", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.TestJSONRequest(t, r, CreateRequestWithOptions) + + w.WriteHeader(http.StatusCreated) + fmt.Fprint(w, GetOutputWithOptions) + }) +} + // HandleUpdateRoleSuccessfully creates an HTTP handler at `/roles` on the // test handler mux that tests role update. func HandleUpdateRoleSuccessfully(t *testing.T, fakeServer th.FakeServer) { diff --git a/openstack/identity/v3/roles/testing/requests_test.go b/openstack/identity/v3/roles/testing/requests_test.go index fb3021064a..88da0a4b44 100644 --- a/openstack/identity/v3/roles/testing/requests_test.go +++ b/openstack/identity/v3/roles/testing/requests_test.go @@ -104,6 +104,27 @@ func TestCreateRole(t *testing.T) { th.CheckDeepEquals(t, SecondRole, *actual) } +func TestCreateWithOptionsRole(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + HandleCreateWithOptionsRoleSuccessfully(t, fakeServer) + + createOpts := roles.CreateOpts{ + Name: "support", + DomainID: "1789d1", + Options: map[roles.Option]any{ + roles.Immutable: true, + }, + Extra: map[string]any{ + "description": "read-only support role", + }, + } + + actual, err := roles.Create(context.TODO(), client.ServiceClient(fakeServer), createOpts).Extract() + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, SecondRoleWithOptions, *actual) +} + func TestUpdateRole(t *testing.T) { fakeServer := th.SetupHTTP() defer fakeServer.Teardown() @@ -113,6 +134,9 @@ func TestUpdateRole(t *testing.T) { Extra: map[string]any{ "description": "admin read-only support role", }, + Options: map[roles.Option]any{ + roles.Immutable: false, + }, } actual, err := roles.Update(context.TODO(), client.ServiceClient(fakeServer), "9fe1d3", updateOpts).Extract() From 398a995fc99b0092e565d901d06eee0537149210 Mon Sep 17 00:00:00 2001 From: ycalansy Date: Tue, 28 Oct 2025 17:13:09 +0000 Subject: [PATCH 265/429] fix: handle Nova create image response for microversion 2.45 and above Since microversion 2.45, the Location header is removed from the create image response. The image ID is now returned in the response body as JSON. CreateImage now reads the response body and stores it in CreateImageResult. The image ID extraction checks X-OpenStack-Nova-API-Version to determine whether to extract the ID from the Location header (< 2.45) or the response body (>= 2.45). --- openstack/compute/v2/servers/requests.go | 29 +++++++++++++++- openstack/compute/v2/servers/results.go | 34 ++++++++++++++++++- .../v2/servers/testing/fixtures_test.go | 31 +++++++++++++++-- .../v2/servers/testing/requests_test.go | 17 ++++++++-- 4 files changed, 103 insertions(+), 8 deletions(-) diff --git a/openstack/compute/v2/servers/requests.go b/openstack/compute/v2/servers/requests.go index 6754d0a939..8d0685997d 100644 --- a/openstack/compute/v2/servers/requests.go +++ b/openstack/compute/v2/servers/requests.go @@ -1,10 +1,12 @@ package servers import ( + "bytes" "context" "encoding/base64" "encoding/json" "fmt" + "io" "maps" "net" "regexp" @@ -1053,10 +1055,35 @@ func CreateImage(ctx context.Context, client *gophercloud.ServiceClient, id stri r.Err = err return } + resp, err := client.Post(ctx, actionURL(client, id), b, nil, &gophercloud.RequestOpts{ - OkCodes: []int{202}, + OkCodes: []int{202}, + KeepResponseBody: true, }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + if r.Err != nil { + return + } + defer resp.Body.Close() + + if v := r.Header.Get("Content-Type"); v != "application/json" { + return + } + + // The response body is expected to be a small JSON object containing only "image_id". + // Read it fully into memory so the response body can be closed immediately. + // If the caller doesn't read from the buffer, it can still be safely garbage collected. + + var buf bytes.Buffer + + _, r.Err = io.Copy(&buf, resp.Body) + if r.Err != nil { + return + } + + r.Body = &buf + return } diff --git a/openstack/compute/v2/servers/results.go b/openstack/compute/v2/servers/results.go index 2685c1c969..f40760dc50 100644 --- a/openstack/compute/v2/servers/results.go +++ b/openstack/compute/v2/servers/results.go @@ -10,6 +10,7 @@ import ( "time" "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/openstack/utils" "github.com/gophercloud/gophercloud/v2/pagination" ) @@ -132,18 +133,49 @@ func (r CreateImageResult) ExtractImageID() (string, error) { if r.Err != nil { return "", r.Err } - // Get the image id from the header + + microversion := r.Header.Get("X-OpenStack-Nova-API-Version") + + major, minor, err := utils.ParseMicroversion(microversion) + if err != nil { + return "", fmt.Errorf("failed to parse X-OpenStack-Nova-API-Version header: %s", err) + } + + // In microversions prior to 2.45, the image ID was provided in the Location header. + if major < 2 || (major == 2 && minor < 45) { + return r.extractImageIDFromLocationHeader() + } + + // Starting from 2.45, it is included in the response body. + return r.extractImageIDFromResponseBody() +} + +func (r CreateImageResult) extractImageIDFromLocationHeader() (string, error) { u, err := url.ParseRequestURI(r.Header.Get("Location")) if err != nil { return "", err } + imageID := path.Base(u.Path) if imageID == "." || imageID == "/" { return "", fmt.Errorf("failed to parse the ID of newly created image: %s", u) } + return imageID, nil } +func (r CreateImageResult) extractImageIDFromResponseBody() (string, error) { + var response struct { + ImageID string `json:"image_id"` + } + + if err := r.ExtractInto(&response); err != nil { + return "", err + } + + return response.ImageID, nil +} + // Server represents a server/instance in the OpenStack cloud. type Server struct { // ID uniquely identifies this server amongst all other servers, diff --git a/openstack/compute/v2/servers/testing/fixtures_test.go b/openstack/compute/v2/servers/testing/fixtures_test.go index 5c5153887a..206e20a53c 100644 --- a/openstack/compute/v2/servers/testing/fixtures_test.go +++ b/openstack/compute/v2/servers/testing/fixtures_test.go @@ -1303,14 +1303,39 @@ func HandleNetworkAddressListSuccessfully(t *testing.T, fakeServer th.FakeServer }) } -// HandleCreateServerImageSuccessfully sets up the test server to respond to a TestCreateServerImage request. -func HandleCreateServerImageSuccessfully(t *testing.T, fakeServer th.FakeServer) { +// HandleCreateServerImageSuccessfullyBeforeMicroversion_2_45 sets up the test server to respond to a TestCreateServerImageBeforeMicroversion_2_45 request. +func HandleCreateServerImageSuccessfullyBeforeMicroversion_2_45(t *testing.T, fakeServer th.FakeServer) string { + imageID := "xxxx-xxxxx-xxxxx-xxxx" + fakeServer.Mux.HandleFunc("/servers/serverimage/action", func(w http.ResponseWriter, r *http.Request) { th.TestMethod(t, r, "POST") th.TestHeader(t, r, "X-Auth-Token", client.TokenID) - w.Header().Add("Location", "https://0.0.0.0/images/xxxx-xxxxx-xxxxx-xxxx") + + w.Header().Set("Location", fmt.Sprintf("https://0.0.0.0/images/%s", imageID)) + w.Header().Set("X-OpenStack-Nova-API-Version", "2.44") w.WriteHeader(http.StatusAccepted) }) + + return imageID +} + +// HandleCreateServerImageSuccessfullySinceMicroversion_2_45 sets up the test server to respond to a TestCreateServerImageSinceMicroversion_2_45 request. +func HandleCreateServerImageSuccessfullySinceMicroversion_2_45(t *testing.T, fakeServer th.FakeServer) string { + imageID := "yyyy-yyyyy-yyyyy-yyyyy" + + fakeServer.Mux.HandleFunc("/servers/serverimage/action", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Set("Content-Type", "application/json") + w.Header().Set("X-OpenStack-Nova-API-Version", "2.45") + w.WriteHeader(http.StatusAccepted) + + _, err := w.Write(fmt.Appendf(nil, `{"image_id":"%s"}`, imageID)) + th.AssertNoErr(t, err) + }) + + return imageID } // HandlePasswordGetSuccessfully sets up the test server to respond to a password Get request. diff --git a/openstack/compute/v2/servers/testing/requests_test.go b/openstack/compute/v2/servers/testing/requests_test.go index 96cb77f14e..7127a09a38 100644 --- a/openstack/compute/v2/servers/testing/requests_test.go +++ b/openstack/compute/v2/servers/testing/requests_test.go @@ -1092,13 +1092,24 @@ func TestListAddressesByNetwork(t *testing.T) { th.CheckEquals(t, 1, pages) } -func TestCreateServerImage(t *testing.T) { +func TestCreateServerImageBeforeMicroversion_2_45(t *testing.T) { fakeServer := th.SetupHTTP() defer fakeServer.Teardown() - HandleCreateServerImageSuccessfully(t, fakeServer) + expected := HandleCreateServerImageSuccessfullyBeforeMicroversion_2_45(t, fakeServer) - _, err := servers.CreateImage(context.TODO(), client.ServiceClient(fakeServer), "serverimage", servers.CreateImageOpts{Name: "test"}).ExtractImageID() + imageID, err := servers.CreateImage(context.TODO(), client.ServiceClient(fakeServer), "serverimage", servers.CreateImageOpts{Name: "test"}).ExtractImageID() th.AssertNoErr(t, err) + th.AssertEquals(t, expected, imageID) +} + +func TestCreateServerImageSinceMicroversion_2_45(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + expected := HandleCreateServerImageSuccessfullySinceMicroversion_2_45(t, fakeServer) + + imageID, err := servers.CreateImage(context.TODO(), client.ServiceClient(fakeServer), "serverimage", servers.CreateImageOpts{Name: "test"}).ExtractImageID() + th.AssertNoErr(t, err) + th.AssertEquals(t, expected, imageID) } func TestMarshalPersonality(t *testing.T) { From 811a469a51a991cbb4f57d96255bafbb434f019d Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Mon, 19 May 2025 10:37:18 +0100 Subject: [PATCH 266/429] Bump Epoxy jobs to Ubuntu 24.04 (Noble) Now that the DevStack fix has landed [1]. [1] https://review.opendev.org/c/openstack/devstack/+/950289 Signed-off-by: Stephen Finucane --- .github/workflows/functional-basic.yaml | 2 +- .github/workflows/functional-blockstorage.yaml | 2 +- .github/workflows/functional-compute.yaml | 2 +- .github/workflows/functional-containerinfra.yaml | 2 +- .github/workflows/functional-dns.yaml | 2 +- .github/workflows/functional-fwaas_v2.yaml | 2 +- .github/workflows/functional-identity.yaml | 2 +- .github/workflows/functional-image.yaml | 2 +- .github/workflows/functional-keymanager.yaml | 2 +- .github/workflows/functional-loadbalancer.yaml | 2 +- .github/workflows/functional-messaging.yaml | 2 +- .github/workflows/functional-networking.yaml | 2 +- .github/workflows/functional-objectstorage.yaml | 2 +- .github/workflows/functional-orchestration.yaml | 2 +- .github/workflows/functional-placement.yaml | 2 +- .github/workflows/functional-sharedfilesystems.yaml | 2 +- .github/workflows/functional-workflow.yaml | 2 +- 17 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.github/workflows/functional-basic.yaml b/.github/workflows/functional-basic.yaml index 70acbf3762..c5e5fdedfd 100644 --- a/.github/workflows/functional-basic.yaml +++ b/.github/workflows/functional-basic.yaml @@ -16,7 +16,7 @@ jobs: additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" - ubuntu_version: "22.04" + ubuntu_version: "24.04" additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" diff --git a/.github/workflows/functional-blockstorage.yaml b/.github/workflows/functional-blockstorage.yaml index 86f7de3671..81562b182c 100644 --- a/.github/workflows/functional-blockstorage.yaml +++ b/.github/workflows/functional-blockstorage.yaml @@ -16,7 +16,7 @@ jobs: additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" - ubuntu_version: "22.04" + ubuntu_version: "24.04" additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" diff --git a/.github/workflows/functional-compute.yaml b/.github/workflows/functional-compute.yaml index 5322a86401..928269cda2 100644 --- a/.github/workflows/functional-compute.yaml +++ b/.github/workflows/functional-compute.yaml @@ -16,7 +16,7 @@ jobs: additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" - ubuntu_version: "22.04" + ubuntu_version: "24.04" additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" diff --git a/.github/workflows/functional-containerinfra.yaml b/.github/workflows/functional-containerinfra.yaml index 6172dccb03..b6cb29fd5e 100644 --- a/.github/workflows/functional-containerinfra.yaml +++ b/.github/workflows/functional-containerinfra.yaml @@ -25,7 +25,7 @@ jobs: additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" - ubuntu_version: "22.04" + ubuntu_version: "24.04" devstack_conf_overrides: | # ensure we're using a working version of setuptools if [ -n "\$TOP_DIR" ]; then diff --git a/.github/workflows/functional-dns.yaml b/.github/workflows/functional-dns.yaml index ee57512203..3446262d23 100644 --- a/.github/workflows/functional-dns.yaml +++ b/.github/workflows/functional-dns.yaml @@ -22,7 +22,7 @@ jobs: additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" - ubuntu_version: "22.04" + ubuntu_version: "24.04" additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" diff --git a/.github/workflows/functional-fwaas_v2.yaml b/.github/workflows/functional-fwaas_v2.yaml index 5e2cadc271..88f7e2a2f2 100644 --- a/.github/workflows/functional-fwaas_v2.yaml +++ b/.github/workflows/functional-fwaas_v2.yaml @@ -20,7 +20,7 @@ jobs: additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" - ubuntu_version: "22.04" + ubuntu_version: "24.04" additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" diff --git a/.github/workflows/functional-identity.yaml b/.github/workflows/functional-identity.yaml index 37622af366..c15fcbe41d 100644 --- a/.github/workflows/functional-identity.yaml +++ b/.github/workflows/functional-identity.yaml @@ -16,7 +16,7 @@ jobs: additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" - ubuntu_version: "22.04" + ubuntu_version: "24.04" additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" diff --git a/.github/workflows/functional-image.yaml b/.github/workflows/functional-image.yaml index c05fad1e80..0c28af851c 100644 --- a/.github/workflows/functional-image.yaml +++ b/.github/workflows/functional-image.yaml @@ -16,7 +16,7 @@ jobs: additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" - ubuntu_version: "22.04" + ubuntu_version: "24.04" additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" diff --git a/.github/workflows/functional-keymanager.yaml b/.github/workflows/functional-keymanager.yaml index 44d9607067..a24aaabf01 100644 --- a/.github/workflows/functional-keymanager.yaml +++ b/.github/workflows/functional-keymanager.yaml @@ -22,7 +22,7 @@ jobs: additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" - ubuntu_version: "22.04" + ubuntu_version: "24.04" devstack_conf_overrides: | # ensure we're using a working version of setuptools if [ -n "\$TOP_DIR" ]; then diff --git a/.github/workflows/functional-loadbalancer.yaml b/.github/workflows/functional-loadbalancer.yaml index 3f73436037..7b0e64937e 100644 --- a/.github/workflows/functional-loadbalancer.yaml +++ b/.github/workflows/functional-loadbalancer.yaml @@ -22,7 +22,7 @@ jobs: additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" - ubuntu_version: "22.04" + ubuntu_version: "24.04" additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" diff --git a/.github/workflows/functional-messaging.yaml b/.github/workflows/functional-messaging.yaml index 0222956e89..8275e912ff 100644 --- a/.github/workflows/functional-messaging.yaml +++ b/.github/workflows/functional-messaging.yaml @@ -16,7 +16,7 @@ jobs: additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" - ubuntu_version: "22.04" + ubuntu_version: "24.04" additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" diff --git a/.github/workflows/functional-networking.yaml b/.github/workflows/functional-networking.yaml index 28107f4fc5..ed0e6ecefe 100644 --- a/.github/workflows/functional-networking.yaml +++ b/.github/workflows/functional-networking.yaml @@ -16,7 +16,7 @@ jobs: additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" - ubuntu_version: "22.04" + ubuntu_version: "24.04" additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" diff --git a/.github/workflows/functional-objectstorage.yaml b/.github/workflows/functional-objectstorage.yaml index fb71022fba..c0b61d85e6 100644 --- a/.github/workflows/functional-objectstorage.yaml +++ b/.github/workflows/functional-objectstorage.yaml @@ -16,7 +16,7 @@ jobs: additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" - ubuntu_version: "22.04" + ubuntu_version: "24.04" additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" diff --git a/.github/workflows/functional-orchestration.yaml b/.github/workflows/functional-orchestration.yaml index 45859d2fac..1c2b60a20d 100644 --- a/.github/workflows/functional-orchestration.yaml +++ b/.github/workflows/functional-orchestration.yaml @@ -16,7 +16,7 @@ jobs: additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" - ubuntu_version: "22.04" + ubuntu_version: "24.04" additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" diff --git a/.github/workflows/functional-placement.yaml b/.github/workflows/functional-placement.yaml index 2219c99a0a..aaf8252c84 100644 --- a/.github/workflows/functional-placement.yaml +++ b/.github/workflows/functional-placement.yaml @@ -16,7 +16,7 @@ jobs: additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" - ubuntu_version: "22.04" + ubuntu_version: "24.04" additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" diff --git a/.github/workflows/functional-sharedfilesystems.yaml b/.github/workflows/functional-sharedfilesystems.yaml index cac6da18da..5c57a53d08 100644 --- a/.github/workflows/functional-sharedfilesystems.yaml +++ b/.github/workflows/functional-sharedfilesystems.yaml @@ -22,7 +22,7 @@ jobs: additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" - ubuntu_version: "22.04" + ubuntu_version: "24.04" additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" diff --git a/.github/workflows/functional-workflow.yaml b/.github/workflows/functional-workflow.yaml index 4ac0dde74d..aff65e5e6f 100644 --- a/.github/workflows/functional-workflow.yaml +++ b/.github/workflows/functional-workflow.yaml @@ -17,7 +17,7 @@ jobs: additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" - ubuntu_version: "22.04" + ubuntu_version: "24.04" mistral_plugin_version: "stable/2025.1" additional_services: "openstack-cli-server" - name: "dalmatian" From 06ae96c3995f6d4718e0d507055aef43cf118428 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 30 Oct 2025 12:23:39 +0000 Subject: [PATCH 267/429] Drop Caracal jobs This is now EOL. Signed-off-by: Stephen Finucane --- .github/workflows/functional-baremetal.yaml | 4 ---- .github/workflows/functional-basic.yaml | 4 ---- .github/workflows/functional-blockstorage.yaml | 4 ---- .github/workflows/functional-compute.yaml | 4 ---- .github/workflows/functional-containerinfra.yaml | 7 ------- .github/workflows/functional-dns.yaml | 4 ---- .github/workflows/functional-fwaas_v2.yaml | 4 ---- .github/workflows/functional-identity.yaml | 4 ---- .github/workflows/functional-image.yaml | 4 ---- .github/workflows/functional-keymanager.yaml | 4 ---- .github/workflows/functional-loadbalancer.yaml | 4 ---- .github/workflows/functional-messaging.yaml | 4 ---- .github/workflows/functional-networking.yaml | 4 ---- .github/workflows/functional-objectstorage.yaml | 4 ---- .github/workflows/functional-orchestration.yaml | 4 ---- .github/workflows/functional-placement.yaml | 4 ---- .github/workflows/functional-sharedfilesystems.yaml | 4 ---- .github/workflows/functional-workflow.yaml | 5 ----- 18 files changed, 76 deletions(-) diff --git a/.github/workflows/functional-baremetal.yaml b/.github/workflows/functional-baremetal.yaml index 341060fbb0..84f020d184 100644 --- a/.github/workflows/functional-baremetal.yaml +++ b/.github/workflows/functional-baremetal.yaml @@ -22,10 +22,6 @@ jobs: openstack_version: "stable/2024.2" ubuntu_version: "22.04" additional_services: "openstack-cli-server" - - name: "caracal" - openstack_version: "stable/2024.1" - ubuntu_version: "22.04" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Ironic on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-basic.yaml b/.github/workflows/functional-basic.yaml index c5e5fdedfd..7c16e6f97d 100644 --- a/.github/workflows/functional-basic.yaml +++ b/.github/workflows/functional-basic.yaml @@ -22,10 +22,6 @@ jobs: openstack_version: "stable/2024.2" ubuntu_version: "22.04" additional_services: "openstack-cli-server" - - name: "caracal" - openstack_version: "stable/2024.1" - ubuntu_version: "22.04" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: basic tests on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-blockstorage.yaml b/.github/workflows/functional-blockstorage.yaml index 81562b182c..ba0571b79f 100644 --- a/.github/workflows/functional-blockstorage.yaml +++ b/.github/workflows/functional-blockstorage.yaml @@ -22,10 +22,6 @@ jobs: openstack_version: "stable/2024.2" ubuntu_version: "22.04" additional_services: "openstack-cli-server" - - name: "caracal" - openstack_version: "stable/2024.1" - ubuntu_version: "22.04" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Cinder on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-compute.yaml b/.github/workflows/functional-compute.yaml index 928269cda2..2fca7a2fd0 100644 --- a/.github/workflows/functional-compute.yaml +++ b/.github/workflows/functional-compute.yaml @@ -22,10 +22,6 @@ jobs: openstack_version: "stable/2024.2" ubuntu_version: "22.04" additional_services: "openstack-cli-server" - - name: "caracal" - openstack_version: "stable/2024.1" - ubuntu_version: "22.04" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Nova on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-containerinfra.yaml b/.github/workflows/functional-containerinfra.yaml index b6cb29fd5e..fa28ceceb6 100644 --- a/.github/workflows/functional-containerinfra.yaml +++ b/.github/workflows/functional-containerinfra.yaml @@ -43,13 +43,6 @@ jobs: enable_plugin magnum https://github.com/openstack/magnum stable/2024.2 MAGNUMCLIENT_BRANCH=stable/2024.2 additional_services: "openstack-cli-server" - - name: "caracal" - openstack_version: "stable/2024.1" - ubuntu_version: "22.04" - devstack_conf_overrides: | - enable_plugin magnum https://github.com/openstack/magnum stable/2024.1 - MAGNUMCLIENT_BRANCH=stable/2024.1 - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Magnum on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-dns.yaml b/.github/workflows/functional-dns.yaml index 3446262d23..afbe468765 100644 --- a/.github/workflows/functional-dns.yaml +++ b/.github/workflows/functional-dns.yaml @@ -28,10 +28,6 @@ jobs: openstack_version: "stable/2024.2" ubuntu_version: "22.04" additional_services: "openstack-cli-server" - - name: "caracal" - openstack_version: "stable/2024.1" - ubuntu_version: "22.04" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Designate on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-fwaas_v2.yaml b/.github/workflows/functional-fwaas_v2.yaml index 88f7e2a2f2..9072610440 100644 --- a/.github/workflows/functional-fwaas_v2.yaml +++ b/.github/workflows/functional-fwaas_v2.yaml @@ -26,10 +26,6 @@ jobs: openstack_version: "stable/2024.2" ubuntu_version: "22.04" additional_services: "openstack-cli-server" - - name: "caracal" - openstack_version: "stable/2024.1" - ubuntu_version: "22.04" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: FWaaS_v2 on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-identity.yaml b/.github/workflows/functional-identity.yaml index c15fcbe41d..90423332e9 100644 --- a/.github/workflows/functional-identity.yaml +++ b/.github/workflows/functional-identity.yaml @@ -22,10 +22,6 @@ jobs: openstack_version: "stable/2024.2" ubuntu_version: "22.04" additional_services: "openstack-cli-server" - - name: "caracal" - openstack_version: "stable/2024.1" - ubuntu_version: "22.04" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Keystone on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-image.yaml b/.github/workflows/functional-image.yaml index 0c28af851c..e6534ce026 100644 --- a/.github/workflows/functional-image.yaml +++ b/.github/workflows/functional-image.yaml @@ -22,10 +22,6 @@ jobs: openstack_version: "stable/2024.2" ubuntu_version: "22.04" additional_services: "openstack-cli-server" - - name: "caracal" - openstack_version: "stable/2024.1" - ubuntu_version: "22.04" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Glance on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-keymanager.yaml b/.github/workflows/functional-keymanager.yaml index a24aaabf01..40da884938 100644 --- a/.github/workflows/functional-keymanager.yaml +++ b/.github/workflows/functional-keymanager.yaml @@ -34,10 +34,6 @@ jobs: openstack_version: "stable/2024.2" ubuntu_version: "22.04" additional_services: "openstack-cli-server" - - name: "caracal" - openstack_version: "stable/2024.1" - ubuntu_version: "22.04" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Barbican on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-loadbalancer.yaml b/.github/workflows/functional-loadbalancer.yaml index 7b0e64937e..e5e3914323 100644 --- a/.github/workflows/functional-loadbalancer.yaml +++ b/.github/workflows/functional-loadbalancer.yaml @@ -28,10 +28,6 @@ jobs: openstack_version: "stable/2024.2" ubuntu_version: "22.04" additional_services: "openstack-cli-server" - - name: "caracal" - openstack_version: "stable/2024.1" - ubuntu_version: "22.04" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Octavia on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-messaging.yaml b/.github/workflows/functional-messaging.yaml index 8275e912ff..c13dd3a5b2 100644 --- a/.github/workflows/functional-messaging.yaml +++ b/.github/workflows/functional-messaging.yaml @@ -22,10 +22,6 @@ jobs: openstack_version: "stable/2024.2" ubuntu_version: "22.04" additional_services: "openstack-cli-server" - - name: "caracal" - openstack_version: "stable/2024.1" - ubuntu_version: "22.04" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Zaqar on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-networking.yaml b/.github/workflows/functional-networking.yaml index ed0e6ecefe..afc0f0de8e 100644 --- a/.github/workflows/functional-networking.yaml +++ b/.github/workflows/functional-networking.yaml @@ -22,10 +22,6 @@ jobs: openstack_version: "stable/2024.2" ubuntu_version: "22.04" additional_services: "openstack-cli-server" - - name: "caracal" - openstack_version: "stable/2024.1" - ubuntu_version: "22.04" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Neutron on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-objectstorage.yaml b/.github/workflows/functional-objectstorage.yaml index c0b61d85e6..82406692a0 100644 --- a/.github/workflows/functional-objectstorage.yaml +++ b/.github/workflows/functional-objectstorage.yaml @@ -22,10 +22,6 @@ jobs: openstack_version: "stable/2024.2" ubuntu_version: "22.04" additional_services: "openstack-cli-server" - - name: "caracal" - openstack_version: "stable/2024.1" - ubuntu_version: "22.04" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Swift on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-orchestration.yaml b/.github/workflows/functional-orchestration.yaml index 1c2b60a20d..9e4242e0bc 100644 --- a/.github/workflows/functional-orchestration.yaml +++ b/.github/workflows/functional-orchestration.yaml @@ -22,10 +22,6 @@ jobs: openstack_version: "stable/2024.2" ubuntu_version: "22.04" additional_services: "openstack-cli-server" - - name: "caracal" - openstack_version: "stable/2024.1" - ubuntu_version: "22.04" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Heat on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-placement.yaml b/.github/workflows/functional-placement.yaml index aaf8252c84..e2655d1daf 100644 --- a/.github/workflows/functional-placement.yaml +++ b/.github/workflows/functional-placement.yaml @@ -22,10 +22,6 @@ jobs: openstack_version: "stable/2024.2" ubuntu_version: "22.04" additional_services: "openstack-cli-server" - - name: "caracal" - openstack_version: "stable/2024.1" - ubuntu_version: "22.04" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Placement on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-sharedfilesystems.yaml b/.github/workflows/functional-sharedfilesystems.yaml index 5c57a53d08..c87cf8d75a 100644 --- a/.github/workflows/functional-sharedfilesystems.yaml +++ b/.github/workflows/functional-sharedfilesystems.yaml @@ -28,10 +28,6 @@ jobs: openstack_version: "stable/2024.2" ubuntu_version: "22.04" additional_services: "openstack-cli-server" - - name: "caracal" - openstack_version: "stable/2024.1" - ubuntu_version: "22.04" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Manila on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-workflow.yaml b/.github/workflows/functional-workflow.yaml index aff65e5e6f..c9f38bc591 100644 --- a/.github/workflows/functional-workflow.yaml +++ b/.github/workflows/functional-workflow.yaml @@ -25,11 +25,6 @@ jobs: ubuntu_version: "22.04" mistral_plugin_version: "stable/2024.2" additional_services: "openstack-cli-server" - - name: "caracal" - openstack_version: "stable/2024.1" - ubuntu_version: "22.04" - mistral_plugin_version: "stable/2024.1" - additional_services: "" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Mistral on Deploy OpenStack ${{ matrix.name }} steps: From 3260d638cc43cfa067de33d2c2790149db2cd538 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 30 Oct 2025 12:24:34 +0000 Subject: [PATCH 268/429] Always enable openstack-cli-server All tested versions of OpenStack now support this allowing us to simplify our jobs. Signed-off-by: Stephen Finucane --- .github/workflows/functional-baremetal.yaml | 5 +---- .github/workflows/functional-basic.yaml | 5 +---- .github/workflows/functional-blockstorage.yaml | 5 +---- .github/workflows/functional-compute.yaml | 5 +---- .github/workflows/functional-containerinfra.yaml | 5 +---- .github/workflows/functional-dns.yaml | 5 +---- .github/workflows/functional-fwaas_v2.yaml | 5 +---- .github/workflows/functional-identity.yaml | 5 +---- .github/workflows/functional-image.yaml | 5 +---- .github/workflows/functional-keymanager.yaml | 5 +---- .github/workflows/functional-loadbalancer.yaml | 5 +---- .github/workflows/functional-messaging.yaml | 5 +---- .github/workflows/functional-networking.yaml | 5 +---- .github/workflows/functional-objectstorage.yaml | 5 +---- .github/workflows/functional-orchestration.yaml | 5 +---- .github/workflows/functional-placement.yaml | 5 +---- .github/workflows/functional-sharedfilesystems.yaml | 5 +---- .github/workflows/functional-workflow.yaml | 5 +---- 18 files changed, 18 insertions(+), 72 deletions(-) diff --git a/.github/workflows/functional-baremetal.yaml b/.github/workflows/functional-baremetal.yaml index 84f020d184..802e886901 100644 --- a/.github/workflows/functional-baremetal.yaml +++ b/.github/workflows/functional-baremetal.yaml @@ -13,15 +13,12 @@ jobs: - name: "master" openstack_version: "master" ubuntu_version: "24.04" - additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" - additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" ubuntu_version: "22.04" - additional_services: "openstack-cli-server" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Ironic on OpenStack ${{ matrix.name }} steps: @@ -96,7 +93,7 @@ jobs: IRONIC_ENABLED_DEPLOY_INTERFACES=direct,fake SWIFT_ENABLE_TEMPURLS=True SWIFT_TEMPURL_KEY=secretkey - enabled_services: "ir-api,ir-cond,s-account,s-container,s-object,s-proxy,q-svc,q-agt,q-dhcp,q-l3,q-meta,-cinder,-c-sch,-c-api,-c-vol,-c-bak,-ovn,-ovn-controller,-ovn-northd,-q-ovn-metadata-agent,${{ matrix.additional_services }}" + enabled_services: "ir-api,ir-cond,s-account,s-container,s-object,s-proxy,q-svc,q-agt,q-dhcp,q-l3,q-meta,-cinder,-c-sch,-c-api,-c-vol,-c-bak,-ovn,-ovn-controller,-ovn-northd,-q-ovn-metadata-agent,openstack-cli-server" - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} diff --git a/.github/workflows/functional-basic.yaml b/.github/workflows/functional-basic.yaml index 7c16e6f97d..7cc97ce2ed 100644 --- a/.github/workflows/functional-basic.yaml +++ b/.github/workflows/functional-basic.yaml @@ -13,15 +13,12 @@ jobs: - name: "master" openstack_version: "master" ubuntu_version: "24.04" - additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" - additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" ubuntu_version: "22.04" - additional_services: "openstack-cli-server" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: basic tests on OpenStack ${{ matrix.name }} steps: @@ -50,7 +47,7 @@ jobs: uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: branch: ${{ matrix.openstack_version }} - enabled_services: 's-account,s-container,s-object,s-proxy,${{ matrix.additional_services }}' + enabled_services: 's-account,s-container,s-object,s-proxy,openstack-cli-server' - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} diff --git a/.github/workflows/functional-blockstorage.yaml b/.github/workflows/functional-blockstorage.yaml index ba0571b79f..4e88bcf39a 100644 --- a/.github/workflows/functional-blockstorage.yaml +++ b/.github/workflows/functional-blockstorage.yaml @@ -13,15 +13,12 @@ jobs: - name: "master" openstack_version: "master" ubuntu_version: "24.04" - additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" - additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" ubuntu_version: "22.04" - additional_services: "openstack-cli-server" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Cinder on OpenStack ${{ matrix.name }} steps: @@ -56,7 +53,7 @@ jobs: branch: ${{ matrix.openstack_version }} conf_overrides: | CINDER_ISCSI_HELPER=lioadm - enabled_services: "s-account,s-container,s-object,s-proxy,c-bak,${{ matrix.additional_services }}" + enabled_services: "s-account,s-container,s-object,s-proxy,c-bak,openstack-cli-server" - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} diff --git a/.github/workflows/functional-compute.yaml b/.github/workflows/functional-compute.yaml index 2fca7a2fd0..c798e9c5b7 100644 --- a/.github/workflows/functional-compute.yaml +++ b/.github/workflows/functional-compute.yaml @@ -13,15 +13,12 @@ jobs: - name: "master" openstack_version: "master" ubuntu_version: "24.04" - additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" - additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" ubuntu_version: "22.04" - additional_services: "openstack-cli-server" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Nova on OpenStack ${{ matrix.name }} steps: @@ -56,7 +53,7 @@ jobs: branch: ${{ matrix.openstack_version }} conf_overrides: | CINDER_ISCSI_HELPER=lioadm - enabled_services: "${{ matrix.additional_services }}" + enabled_services: "openstack-cli-server" - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} diff --git a/.github/workflows/functional-containerinfra.yaml b/.github/workflows/functional-containerinfra.yaml index fa28ceceb6..c672171b46 100644 --- a/.github/workflows/functional-containerinfra.yaml +++ b/.github/workflows/functional-containerinfra.yaml @@ -22,7 +22,6 @@ jobs: enable_plugin magnum https://github.com/openstack/magnum master MAGNUMCLIENT_BRANCH=master - additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" @@ -35,14 +34,12 @@ jobs: enable_plugin magnum https://github.com/openstack/magnum stable/2025.1 MAGNUMCLIENT_BRANCH=stable/2025.1 - additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" ubuntu_version: "22.04" devstack_conf_overrides: | enable_plugin magnum https://github.com/openstack/magnum stable/2024.2 MAGNUMCLIENT_BRANCH=stable/2024.2 - additional_services: "openstack-cli-server" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Magnum on OpenStack ${{ matrix.name }} steps: @@ -83,7 +80,7 @@ jobs: KEYSTONE_ADMIN_ENDPOINT=true ${{ matrix.devstack_conf_overrides }} - enabled_services: "h-eng,h-api,h-api-cfn,h-api-cw,${{ matrix.additional_services }}" + enabled_services: "h-eng,h-api,h-api-cfn,h-api-cw,openstack-cli-server" - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} diff --git a/.github/workflows/functional-dns.yaml b/.github/workflows/functional-dns.yaml index afbe468765..e4aa1e8caa 100644 --- a/.github/workflows/functional-dns.yaml +++ b/.github/workflows/functional-dns.yaml @@ -19,15 +19,12 @@ jobs: sed -i 's/setuptools\[core\]$/setuptools[core]==79.0.1/g' \$TOP_DIR/lib/infra \$TOP_DIR/inc/python sed -i 's/pip_install "-U" "pbr"/pip_install "-U" "pbr" "setuptools[core]==79.0.1"/g' \$TOP_DIR/lib/infra fi - additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" - additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" ubuntu_version: "22.04" - additional_services: "openstack-cli-server" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Designate on OpenStack ${{ matrix.name }} steps: @@ -64,7 +61,7 @@ jobs: enable_plugin designate https://github.com/openstack/designate ${{ matrix.openstack_version }} ${{ matrix.devstack_conf_overrides }} - enabled_services: "designate,designate-central,designate-api,designate-worker,designate-producer,designate-mdns,${{ matrix.additional_services }}" + enabled_services: "designate,designate-central,designate-api,designate-worker,designate-producer,designate-mdns,openstack-cli-server" - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} diff --git a/.github/workflows/functional-fwaas_v2.yaml b/.github/workflows/functional-fwaas_v2.yaml index 9072610440..4d722a5d52 100644 --- a/.github/workflows/functional-fwaas_v2.yaml +++ b/.github/workflows/functional-fwaas_v2.yaml @@ -17,15 +17,12 @@ jobs: - name: "master" openstack_version: "master" ubuntu_version: "24.04" - additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" - additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" ubuntu_version: "22.04" - additional_services: "openstack-cli-server" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: FWaaS_v2 on OpenStack ${{ matrix.name }} steps: @@ -79,7 +76,7 @@ jobs: [[post-config|\$NEUTRON_CONF]] [oslo_policy] policy_dirs = /tmp/neutron-policies - enabled_services: 'q-svc,q-agt,q-dhcp,q-l3,q-meta,q-fwaas-v2,-cinder,-horizon,-tempest,-swift,-c-sch,-c-api,-c-vol,-c-bak,-ovn,-ovn-controller,-ovn-northd,-q-ovn-metadata-agent,${{ matrix.additional_services }}' + enabled_services: 'q-svc,q-agt,q-dhcp,q-l3,q-meta,q-fwaas-v2,-cinder,-horizon,-tempest,-swift,-c-sch,-c-api,-c-vol,-c-bak,-ovn,-ovn-controller,-ovn-northd,-q-ovn-metadata-agent,openstack-cli-server' - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} diff --git a/.github/workflows/functional-identity.yaml b/.github/workflows/functional-identity.yaml index 90423332e9..7ad9b1cc2f 100644 --- a/.github/workflows/functional-identity.yaml +++ b/.github/workflows/functional-identity.yaml @@ -13,15 +13,12 @@ jobs: - name: "master" openstack_version: "master" ubuntu_version: "24.04" - additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" - additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" ubuntu_version: "22.04" - additional_services: "openstack-cli-server" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Keystone on OpenStack ${{ matrix.name }} steps: @@ -54,7 +51,7 @@ jobs: uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: branch: ${{ matrix.openstack_version }} - enabled_services: "${{ matrix.additional_services }}" + enabled_services: "openstack-cli-server" - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} diff --git a/.github/workflows/functional-image.yaml b/.github/workflows/functional-image.yaml index e6534ce026..1730a3e896 100644 --- a/.github/workflows/functional-image.yaml +++ b/.github/workflows/functional-image.yaml @@ -13,15 +13,12 @@ jobs: - name: "master" openstack_version: "master" ubuntu_version: "24.04" - additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" - additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" ubuntu_version: "22.04" - additional_services: "openstack-cli-server" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Glance on OpenStack ${{ matrix.name }} steps: @@ -54,7 +51,7 @@ jobs: uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: branch: ${{ matrix.openstack_version }} - enabled_services: "${{ matrix.additional_services }}" + enabled_services: "openstack-cli-server" - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} diff --git a/.github/workflows/functional-keymanager.yaml b/.github/workflows/functional-keymanager.yaml index 40da884938..cbc2ddbc13 100644 --- a/.github/workflows/functional-keymanager.yaml +++ b/.github/workflows/functional-keymanager.yaml @@ -19,7 +19,6 @@ jobs: sed -i 's/setuptools\[core\]$/setuptools[core]==79.0.1/g' \$TOP_DIR/lib/infra \$TOP_DIR/inc/python sed -i 's/pip_install "-U" "pbr"/pip_install "-U" "pbr" "setuptools[core]==79.0.1"/g' \$TOP_DIR/lib/infra fi - additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" @@ -29,11 +28,9 @@ jobs: sed -i 's/setuptools\[core\]$/setuptools[core]==79.0.1/g' \$TOP_DIR/lib/infra \$TOP_DIR/inc/python sed -i 's/pip_install "-U" "pbr"/pip_install "-U" "pbr" "setuptools[core]==79.0.1"/g' \$TOP_DIR/lib/infra fi - additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" ubuntu_version: "22.04" - additional_services: "openstack-cli-server" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Barbican on OpenStack ${{ matrix.name }} steps: @@ -70,7 +67,7 @@ jobs: enable_plugin barbican https://github.com/openstack/barbican ${{ matrix.openstack_version }} ${{ matrix.devstack_conf_overrides }} - enabled_services: "barbican-svc,barbican-retry,barbican-keystone-listener,${{ matrix.additional_services }}" + enabled_services: "barbican-svc,barbican-retry,barbican-keystone-listener,openstack-cli-server" - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} diff --git a/.github/workflows/functional-loadbalancer.yaml b/.github/workflows/functional-loadbalancer.yaml index e5e3914323..448b3b94fd 100644 --- a/.github/workflows/functional-loadbalancer.yaml +++ b/.github/workflows/functional-loadbalancer.yaml @@ -19,15 +19,12 @@ jobs: sed -i 's/setuptools\[core\]$/setuptools[core]==79.0.1/g' \$TOP_DIR/lib/infra \$TOP_DIR/inc/python sed -i 's/pip_install "-U" "pbr"/pip_install "-U" "pbr" "setuptools[core]==79.0.1"/g' \$TOP_DIR/lib/infra fi - additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" - additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" ubuntu_version: "22.04" - additional_services: "openstack-cli-server" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Octavia on OpenStack ${{ matrix.name }} steps: @@ -65,7 +62,7 @@ jobs: enable_plugin neutron https://github.com/openstack/neutron ${{ matrix.openstack_version }} ${{ matrix.devstack_conf_overrides }} - enabled_services: "octavia,o-api,o-cw,o-hk,o-hm,o-da,neutron-qos,${{ matrix.additional_services }}" + enabled_services: "octavia,o-api,o-cw,o-hk,o-hm,o-da,neutron-qos,openstack-cli-server" - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} diff --git a/.github/workflows/functional-messaging.yaml b/.github/workflows/functional-messaging.yaml index c13dd3a5b2..3dc6ee7e31 100644 --- a/.github/workflows/functional-messaging.yaml +++ b/.github/workflows/functional-messaging.yaml @@ -13,15 +13,12 @@ jobs: - name: "master" openstack_version: "master" ubuntu_version: "24.04" - additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" - additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" ubuntu_version: "22.04" - additional_services: "openstack-cli-server" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Zaqar on OpenStack ${{ matrix.name }} steps: @@ -57,7 +54,7 @@ jobs: conf_overrides: | enable_plugin zaqar https://github.com/openstack/zaqar ${{ matrix.openstack_version }} ZAQARCLIENT_BRANCH=${{ matrix.openstack_version }} - enabled_services: "${{ matrix.additional_services }}" + enabled_services: "openstack-cli-server" - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} diff --git a/.github/workflows/functional-networking.yaml b/.github/workflows/functional-networking.yaml index afc0f0de8e..7403f829b9 100644 --- a/.github/workflows/functional-networking.yaml +++ b/.github/workflows/functional-networking.yaml @@ -13,15 +13,12 @@ jobs: - name: "master" openstack_version: "master" ubuntu_version: "24.04" - additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" - additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" ubuntu_version: "22.04" - additional_services: "openstack-cli-server" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Neutron on OpenStack ${{ matrix.name }} steps: @@ -74,7 +71,7 @@ jobs: [[post-config|\$NEUTRON_CONF]] [oslo_policy] policy_dirs = /tmp/neutron-policies - enabled_services: "neutron-dns,neutron-qos,neutron-segments,neutron-trunk,neutron-uplink-status-propagation,neutron-network-segment-range,neutron-port-forwarding,${{ matrix.additional_services }}" + enabled_services: "neutron-dns,neutron-qos,neutron-segments,neutron-trunk,neutron-uplink-status-propagation,neutron-network-segment-range,neutron-port-forwarding,openstack-cli-server" - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} diff --git a/.github/workflows/functional-objectstorage.yaml b/.github/workflows/functional-objectstorage.yaml index 82406692a0..7cae7e9200 100644 --- a/.github/workflows/functional-objectstorage.yaml +++ b/.github/workflows/functional-objectstorage.yaml @@ -13,15 +13,12 @@ jobs: - name: "master" openstack_version: "master" ubuntu_version: "24.04" - additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" - additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" ubuntu_version: "22.04" - additional_services: "openstack-cli-server" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Swift on OpenStack ${{ matrix.name }} steps: @@ -60,7 +57,7 @@ jobs: [[post-config|\$SWIFT_CONFIG_PROXY_SERVER]] [filter:versioned_writes] allow_object_versioning = true - enabled_services: 's-account,s-container,s-object,s-proxy,${{ matrix.additional_services }}' + enabled_services: 's-account,s-container,s-object,s-proxy,openstack-cli-server' - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} diff --git a/.github/workflows/functional-orchestration.yaml b/.github/workflows/functional-orchestration.yaml index 9e4242e0bc..10b811570e 100644 --- a/.github/workflows/functional-orchestration.yaml +++ b/.github/workflows/functional-orchestration.yaml @@ -13,15 +13,12 @@ jobs: - name: "master" openstack_version: "master" ubuntu_version: "24.04" - additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" - additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" ubuntu_version: "22.04" - additional_services: "openstack-cli-server" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Heat on OpenStack ${{ matrix.name }} steps: @@ -56,7 +53,7 @@ jobs: branch: ${{ matrix.openstack_version }} conf_overrides: | enable_plugin heat https://github.com/openstack/heat ${{ matrix.openstack_version }} - enabled_services: 'h-eng,h-api,h-api-cfn,h-api-cw,${{ matrix.additional_services }}' + enabled_services: 'h-eng,h-api,h-api-cfn,h-api-cw,openstack-cli-server' - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} diff --git a/.github/workflows/functional-placement.yaml b/.github/workflows/functional-placement.yaml index e2655d1daf..418a1945f0 100644 --- a/.github/workflows/functional-placement.yaml +++ b/.github/workflows/functional-placement.yaml @@ -13,15 +13,12 @@ jobs: - name: "master" openstack_version: "master" ubuntu_version: "24.04" - additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" - additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" ubuntu_version: "22.04" - additional_services: "openstack-cli-server" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Placement on OpenStack ${{ matrix.name }} steps: @@ -54,7 +51,7 @@ jobs: uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 with: branch: ${{ matrix.openstack_version }} - enabled_services: "${{ matrix.additional_services }}" + enabled_services: "openstack-cli-server" - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} diff --git a/.github/workflows/functional-sharedfilesystems.yaml b/.github/workflows/functional-sharedfilesystems.yaml index c87cf8d75a..05ab3337af 100644 --- a/.github/workflows/functional-sharedfilesystems.yaml +++ b/.github/workflows/functional-sharedfilesystems.yaml @@ -19,15 +19,12 @@ jobs: sed -i 's/setuptools\[core\]$/setuptools[core]==79.0.1/g' \$TOP_DIR/lib/infra \$TOP_DIR/inc/python sed -i 's/pip_install "-U" "pbr"/pip_install "-U" "pbr" "setuptools[core]==79.0.1"/g' \$TOP_DIR/lib/infra fi - additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" - additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" ubuntu_version: "22.04" - additional_services: "openstack-cli-server" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Manila on OpenStack ${{ matrix.name }} steps: @@ -78,7 +75,7 @@ jobs: MANILA_INSTALL_TEMPEST_PLUGIN_SYSTEMWIDE=false ${{ matrix.devstack_conf_overrides }} - enabled_services: "${{ matrix.additional_services }}" + enabled_services: "openstack-cli-server" - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} diff --git a/.github/workflows/functional-workflow.yaml b/.github/workflows/functional-workflow.yaml index c9f38bc591..5a2735e1f5 100644 --- a/.github/workflows/functional-workflow.yaml +++ b/.github/workflows/functional-workflow.yaml @@ -14,17 +14,14 @@ jobs: openstack_version: "master" ubuntu_version: "24.04" mistral_plugin_version: "master" - additional_services: "openstack-cli-server" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" mistral_plugin_version: "stable/2025.1" - additional_services: "openstack-cli-server" - name: "dalmatian" openstack_version: "stable/2024.2" ubuntu_version: "22.04" mistral_plugin_version: "stable/2024.2" - additional_services: "openstack-cli-server" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Mistral on Deploy OpenStack ${{ matrix.name }} steps: @@ -59,7 +56,7 @@ jobs: branch: ${{ matrix.openstack_version }} conf_overrides: | enable_plugin mistral https://github.com/openstack/mistral ${{ matrix.mistral_plugin_version }} - enabled_services: "mistral,mistral-api,mistral-engine,mistral-executor,mistral-event-engine,${{ matrix.additional_services }}" + enabled_services: "mistral,mistral-api,mistral-engine,mistral-executor,mistral-event-engine,openstack-cli-server" - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} From 86e7a03fabfe7fd6c6c223eb16de1f1da177c1d2 Mon Sep 17 00:00:00 2001 From: Vladimir Ermakov Date: Fri, 31 Oct 2025 10:47:00 +0100 Subject: [PATCH 269/429] compute: add cpu info topology cells entry Fix #3545 Signed-off-by: Vladimir Ermakov --- openstack/compute/v2/hypervisors/results.go | 1 + 1 file changed, 1 insertion(+) diff --git a/openstack/compute/v2/hypervisors/results.go b/openstack/compute/v2/hypervisors/results.go index cb442a9b61..a6a5d86028 100644 --- a/openstack/compute/v2/hypervisors/results.go +++ b/openstack/compute/v2/hypervisors/results.go @@ -11,6 +11,7 @@ import ( // Topology represents a CPU Topology. type Topology struct { + Cells int `json:"cells"` Sockets int `json:"sockets"` Cores int `json:"cores"` Threads int `json:"threads"` From 62a7ff0414487fc1248c81a2327ff6ea5d399fcc Mon Sep 17 00:00:00 2001 From: Samuel Kunkel Date: Thu, 16 Oct 2025 19:08:54 +0200 Subject: [PATCH 270/429] Add config_drive to server struct Adds config_drive to the regular server struct used for responses. (currently only part of createOpts) which leads to situation that one can create a server with a config_drive. But one can not verify / see that information in any kind of response. This fixes #3534. --- openstack/compute/v2/servers/results.go | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/openstack/compute/v2/servers/results.go b/openstack/compute/v2/servers/results.go index 2685c1c969..25595a28fe 100644 --- a/openstack/compute/v2/servers/results.go +++ b/openstack/compute/v2/servers/results.go @@ -7,6 +7,7 @@ import ( "fmt" "net/url" "path" + "strconv" "time" "github.com/gophercloud/gophercloud/v2" @@ -283,6 +284,9 @@ type Server struct { // Locked indicates the lock status of the server // This requires microversion 2.9 or later Locked *bool `json:"locked"` + + // ConfigDrive enables metadata injection through a configuration drive. + ConfigDrive bool `json:"-"` } type AttachedVolume struct { @@ -343,6 +347,7 @@ func (r *Server) UnmarshalJSON(b []byte) error { Image any `json:"image"` LaunchedAt gophercloud.JSONRFC3339MilliNoZ `json:"OS-SRV-USG:launched_at"` TerminatedAt gophercloud.JSONRFC3339MilliNoZ `json:"OS-SRV-USG:terminated_at"` + ConfigDrive any `json:"config_drive"` } err := json.Unmarshal(b, &s) if err != nil { @@ -364,6 +369,24 @@ func (r *Server) UnmarshalJSON(b []byte) error { r.LaunchedAt = time.Time(s.LaunchedAt) r.TerminatedAt = time.Time(s.TerminatedAt) + switch t := s.ConfigDrive.(type) { + case nil: + r.ConfigDrive = false + case bool: + r.ConfigDrive = t + case string: + if t == "" { + r.ConfigDrive = false + } else { + r.ConfigDrive, err = strconv.ParseBool(t) + if err != nil { + return fmt.Errorf("failed to parse ConfigDrive %q: %v", t, err) + } + } + default: + return fmt.Errorf("unknown type for ConfigDrive: %T (value: %v)", t, t) + } + return err } From c16fa097f6717c90a026166b732f1ddca813629f Mon Sep 17 00:00:00 2001 From: dlawton Date: Fri, 10 Oct 2025 15:15:19 +0100 Subject: [PATCH 271/429] Identity: Add description field to roles. Signed-off-by: Daniel Lawton --- .../openstack/identity/v3/roles_test.go | 16 +++++++----- openstack/identity/v3/roles/requests.go | 8 +++++- openstack/identity/v3/roles/results.go | 3 +++ .../v3/roles/testing/fixtures_test.go | 25 +++++++++++++------ .../v3/roles/testing/requests_test.go | 16 ++++++------ 5 files changed, 47 insertions(+), 21 deletions(-) diff --git a/internal/acceptance/openstack/identity/v3/roles_test.go b/internal/acceptance/openstack/identity/v3/roles_test.go index 96337dc4c1..753736843a 100644 --- a/internal/acceptance/openstack/identity/v3/roles_test.go +++ b/internal/acceptance/openstack/identity/v3/roles_test.go @@ -58,10 +58,11 @@ func TestRolesCRUD(t *testing.T) { th.AssertNoErr(t, err) createOpts := roles.CreateOpts{ - Name: "testrole", - DomainID: "default", + Name: "role-test", + DomainID: "default", + Description: "test description", Extra: map[string]any{ - "description": "test role description", + "email": "testrole@example.com", }, Options: map[roles.Option]any{ "immutable": false, @@ -96,10 +97,11 @@ func TestRolesCRUD(t *testing.T) { } th.AssertEquals(t, found, true) - + description := "updated role test" updateOpts := roles.UpdateOpts{ + Description: &description, Extra: map[string]any{ - "description": "updated test role description", + "email": "updatedtestrole@example.com", }, Options: map[roles.Option]any{ "immutable": nil, @@ -112,7 +114,9 @@ func TestRolesCRUD(t *testing.T) { tools.PrintResource(t, newRole) tools.PrintResource(t, newRole.Extra) - th.AssertEquals(t, newRole.Extra["description"], "updated test role description") + th.AssertEquals(t, newRole.Description, description) + th.AssertEquals(t, newRole.Extra["email"], "updatedtestrole@example.com") + } func TestRolesFilterList(t *testing.T) { diff --git a/openstack/identity/v3/roles/requests.go b/openstack/identity/v3/roles/requests.go index 0552dc2852..260aa153ce 100644 --- a/openstack/identity/v3/roles/requests.go +++ b/openstack/identity/v3/roles/requests.go @@ -94,6 +94,9 @@ type CreateOpts struct { // DomainID is the ID of the domain the role belongs to. DomainID string `json:"domain_id,omitempty"` + // Description is the description of the new role. + Description string `json:"description,omitempty"` + // Extra is free-form extra key/value pairs to describe the role. Extra map[string]any `json:"-"` @@ -141,9 +144,12 @@ type UpdateOptsBuilder interface { // UpdateOpts provides options for updating a role. type UpdateOpts struct { - // Name is the name of the new role. + // Name is an updated name for the role. Name string `json:"name,omitempty"` + // Description is an updated description for the role. + Description *string `json:"description,omitempty"` + // Extra is free-form extra key/value pairs to describe the role. Extra map[string]any `json:"-"` diff --git a/openstack/identity/v3/roles/results.go b/openstack/identity/v3/roles/results.go index b2e348df06..cf9d1cb99e 100644 --- a/openstack/identity/v3/roles/results.go +++ b/openstack/identity/v3/roles/results.go @@ -21,6 +21,9 @@ type Role struct { // Name is the role name Name string `json:"name"` + // Description is the description of the role. + Description string `json:"description"` + // Extra is a collection of miscellaneous key/values. Extra map[string]any `json:"-"` diff --git a/openstack/identity/v3/roles/testing/fixtures_test.go b/openstack/identity/v3/roles/testing/fixtures_test.go index 3fa6171c1b..7cb374d2d7 100644 --- a/openstack/identity/v3/roles/testing/fixtures_test.go +++ b/openstack/identity/v3/roles/testing/fixtures_test.go @@ -34,8 +34,9 @@ const ListOutput = ` "self": "https://example.com/identity/v3/roles/9fe1d3" }, "name": "support", + "description": "read-only support role", "extra": { - "description": "read-only support role" + "test": "this is for the test" } } ] @@ -52,7 +53,10 @@ const GetOutput = ` "self": "https://example.com/identity/v3/roles/9fe1d3" }, "name": "support", - "description": "read-only support role" + "description": "read-only support role", + "extra": { + "test": "this is for the test" + } } } ` @@ -70,6 +74,9 @@ const GetOutputWithOptions = ` "description": "read-only support role", "options": { "immutable": true + }, + "extra": { + "test": "this is for the test" } } } @@ -81,7 +88,8 @@ const CreateRequest = ` "role": { "domain_id": "1789d1", "name": "support", - "description": "read-only support role" + "description": "read-only support role", + "test": "this is for the test" } } ` @@ -93,6 +101,7 @@ const CreateRequestWithOptions = ` "domain_id": "1789d1", "name": "support", "description": "read-only support role", + "test": "this is for the test", "options": { "immutable": true } @@ -354,9 +363,10 @@ var SecondRole = roles.Role{ Links: map[string]any{ "self": "https://example.com/identity/v3/roles/9fe1d3", }, - Name: "support", + Name: "support", + Description: "read-only support role", Extra: map[string]any{ - "description": "read-only support role", + "test": "this is for the test", }, } @@ -367,9 +377,10 @@ var SecondRoleWithOptions = roles.Role{ Links: map[string]any{ "self": "https://example.com/identity/v3/roles/9fe1d3", }, - Name: "support", + Name: "support", + Description: "read-only support role", Extra: map[string]any{ - "description": "read-only support role", + "test": "this is for the test", }, Options: map[roles.Option]any{ roles.Immutable: true, diff --git a/openstack/identity/v3/roles/testing/requests_test.go b/openstack/identity/v3/roles/testing/requests_test.go index 88da0a4b44..7ef5085904 100644 --- a/openstack/identity/v3/roles/testing/requests_test.go +++ b/openstack/identity/v3/roles/testing/requests_test.go @@ -40,7 +40,7 @@ func TestListRolesAllPages(t *testing.T) { actual, err := roles.ExtractRoles(allPages) th.AssertNoErr(t, err) th.CheckDeepEquals(t, ExpectedRolesSlice, actual) - th.AssertEquals(t, ExpectedRolesSlice[1].Extra["description"], "read-only support role") + th.AssertEquals(t, ExpectedRolesSlice[1].Extra["test"], "this is for the test") } func TestListUsersFiltersCheck(t *testing.T) { @@ -92,10 +92,11 @@ func TestCreateRole(t *testing.T) { HandleCreateRoleSuccessfully(t, fakeServer) createOpts := roles.CreateOpts{ - Name: "support", - DomainID: "1789d1", + Name: "support", + DomainID: "1789d1", + Description: "read-only support role", Extra: map[string]any{ - "description": "read-only support role", + "test": "this is for the test", }, } @@ -110,13 +111,14 @@ func TestCreateWithOptionsRole(t *testing.T) { HandleCreateWithOptionsRoleSuccessfully(t, fakeServer) createOpts := roles.CreateOpts{ - Name: "support", - DomainID: "1789d1", + Name: "support", + DomainID: "1789d1", + Description: "read-only support role", Options: map[roles.Option]any{ roles.Immutable: true, }, Extra: map[string]any{ - "description": "read-only support role", + "test": "this is for the test", }, } From 119c76f867d1c4d8c1bb6a17640c82cb87bb7aa8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Nov 2025 12:45:36 +0000 Subject: [PATCH 272/429] build(deps): bump github/codeql-action from 3 to 4 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3 to 4. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/v3...v4) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: '4' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql-analysis.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yaml b/.github/workflows/codeql-analysis.yaml index b24893a9e5..52619c3d30 100644 --- a/.github/workflows/codeql-analysis.yaml +++ b/.github/workflows/codeql-analysis.yaml @@ -27,12 +27,12 @@ jobs: cache: true - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@v3 + uses: github/codeql-action/autobuild@v4 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@v4 From d17c4aa75ad89c5e07493bcb33d4cb61926267bb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Nov 2025 12:54:39 +0000 Subject: [PATCH 273/429] build(deps): bump actions/upload-artifact from 4 to 5 Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 5. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/functional-baremetal.yaml | 2 +- .github/workflows/functional-basic.yaml | 2 +- .github/workflows/functional-blockstorage.yaml | 2 +- .github/workflows/functional-compute.yaml | 2 +- .github/workflows/functional-containerinfra.yaml | 2 +- .github/workflows/functional-dns.yaml | 2 +- .github/workflows/functional-fwaas_v2.yaml | 2 +- .github/workflows/functional-identity.yaml | 2 +- .github/workflows/functional-image.yaml | 2 +- .github/workflows/functional-keymanager.yaml | 2 +- .github/workflows/functional-loadbalancer.yaml | 2 +- .github/workflows/functional-messaging.yaml | 2 +- .github/workflows/functional-networking.yaml | 2 +- .github/workflows/functional-objectstorage.yaml | 2 +- .github/workflows/functional-orchestration.yaml | 2 +- .github/workflows/functional-placement.yaml | 2 +- .github/workflows/functional-sharedfilesystems.yaml | 2 +- .github/workflows/functional-workflow.yaml | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/functional-baremetal.yaml b/.github/workflows/functional-baremetal.yaml index 802e886901..d90653c08c 100644 --- a/.github/workflows/functional-baremetal.yaml +++ b/.github/workflows/functional-baremetal.yaml @@ -119,7 +119,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: functional-baremetal-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-basic.yaml b/.github/workflows/functional-basic.yaml index 7cc97ce2ed..31df68c284 100644 --- a/.github/workflows/functional-basic.yaml +++ b/.github/workflows/functional-basic.yaml @@ -72,7 +72,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: functional-basic-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-blockstorage.yaml b/.github/workflows/functional-blockstorage.yaml index 4e88bcf39a..2e37c98529 100644 --- a/.github/workflows/functional-blockstorage.yaml +++ b/.github/workflows/functional-blockstorage.yaml @@ -78,7 +78,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: functional-blockstorage-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-compute.yaml b/.github/workflows/functional-compute.yaml index c798e9c5b7..455a514a5b 100644 --- a/.github/workflows/functional-compute.yaml +++ b/.github/workflows/functional-compute.yaml @@ -78,7 +78,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: functional-compute-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-containerinfra.yaml b/.github/workflows/functional-containerinfra.yaml index c672171b46..ebfbbcf57f 100644 --- a/.github/workflows/functional-containerinfra.yaml +++ b/.github/workflows/functional-containerinfra.yaml @@ -105,7 +105,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: functional-containerinfra-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-dns.yaml b/.github/workflows/functional-dns.yaml index e4aa1e8caa..8c9a837a15 100644 --- a/.github/workflows/functional-dns.yaml +++ b/.github/workflows/functional-dns.yaml @@ -86,7 +86,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: functional-dns-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-fwaas_v2.yaml b/.github/workflows/functional-fwaas_v2.yaml index 4d722a5d52..e9c8a4a34b 100644 --- a/.github/workflows/functional-fwaas_v2.yaml +++ b/.github/workflows/functional-fwaas_v2.yaml @@ -101,7 +101,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: functional-fwaas_v2-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-identity.yaml b/.github/workflows/functional-identity.yaml index 7ad9b1cc2f..381e1b79da 100644 --- a/.github/workflows/functional-identity.yaml +++ b/.github/workflows/functional-identity.yaml @@ -76,7 +76,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: functional-identity-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-image.yaml b/.github/workflows/functional-image.yaml index 1730a3e896..646d9f5f4e 100644 --- a/.github/workflows/functional-image.yaml +++ b/.github/workflows/functional-image.yaml @@ -76,7 +76,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: functional-image-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-keymanager.yaml b/.github/workflows/functional-keymanager.yaml index cbc2ddbc13..f573423523 100644 --- a/.github/workflows/functional-keymanager.yaml +++ b/.github/workflows/functional-keymanager.yaml @@ -92,7 +92,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: functional-keymanager-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-loadbalancer.yaml b/.github/workflows/functional-loadbalancer.yaml index 448b3b94fd..2dad9a65bb 100644 --- a/.github/workflows/functional-loadbalancer.yaml +++ b/.github/workflows/functional-loadbalancer.yaml @@ -87,7 +87,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: functional-loadbalancer-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-messaging.yaml b/.github/workflows/functional-messaging.yaml index 3dc6ee7e31..80da8e09cc 100644 --- a/.github/workflows/functional-messaging.yaml +++ b/.github/workflows/functional-messaging.yaml @@ -79,7 +79,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: functional-messaging-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-networking.yaml b/.github/workflows/functional-networking.yaml index 7403f829b9..be1a694d81 100644 --- a/.github/workflows/functional-networking.yaml +++ b/.github/workflows/functional-networking.yaml @@ -96,7 +96,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: functional-networking-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-objectstorage.yaml b/.github/workflows/functional-objectstorage.yaml index 7cae7e9200..118a0b14a9 100644 --- a/.github/workflows/functional-objectstorage.yaml +++ b/.github/workflows/functional-objectstorage.yaml @@ -82,7 +82,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: functional-objectstorage-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-orchestration.yaml b/.github/workflows/functional-orchestration.yaml index 10b811570e..4c7f772d1e 100644 --- a/.github/workflows/functional-orchestration.yaml +++ b/.github/workflows/functional-orchestration.yaml @@ -78,7 +78,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: functional-orchestration-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-placement.yaml b/.github/workflows/functional-placement.yaml index 418a1945f0..eebbcc5091 100644 --- a/.github/workflows/functional-placement.yaml +++ b/.github/workflows/functional-placement.yaml @@ -76,7 +76,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: functional-placement-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-sharedfilesystems.yaml b/.github/workflows/functional-sharedfilesystems.yaml index 05ab3337af..17f7108f74 100644 --- a/.github/workflows/functional-sharedfilesystems.yaml +++ b/.github/workflows/functional-sharedfilesystems.yaml @@ -100,7 +100,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: functional-sharedfilesystems-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-workflow.yaml b/.github/workflows/functional-workflow.yaml index 5a2735e1f5..df597a74f7 100644 --- a/.github/workflows/functional-workflow.yaml +++ b/.github/workflows/functional-workflow.yaml @@ -81,7 +81,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: functional-workflow-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* From 69bd65e2885f61bedb69842427eb450424326343 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Fri, 14 Nov 2025 08:35:03 +0100 Subject: [PATCH 274/429] Fix EC2 authentication to work with new Keystone auth requirement Keystone recently changed to require authentication for the EC2 tokens endpoint [1]. Previously, the EC2 tokens endpoint could be accessed without authentication, but now it requires a valid token. Fixes #3555 [1] https://review.opendev.org/q/Ic84b84247e05f29874e2c5636a033aaedd4de83c --- internal/acceptance/openstack/client_test.go | 3 ++- openstack/identity/v3/ec2tokens/requests.go | 6 ++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/internal/acceptance/openstack/client_test.go b/internal/acceptance/openstack/client_test.go index ccef68855f..3a732d42ba 100644 --- a/internal/acceptance/openstack/client_test.go +++ b/internal/acceptance/openstack/client_test.go @@ -94,7 +94,8 @@ func TestEC2AuthMethod(t *testing.T) { defer credentials.Delete(context.TODO(), client, credential.ID) tools.PrintResource(t, credential) - newClient, err := clients.NewIdentityV3UnauthenticatedClient() + // Create a new provider client for EC2 authentication using the existing token + newClient, err := clients.NewIdentityV3Client() th.AssertNoErr(t, err) ec2AuthOptions := &ec2tokens.AuthOptions{ diff --git a/openstack/identity/v3/ec2tokens/requests.go b/openstack/identity/v3/ec2tokens/requests.go index 5b1f3d6882..1d4cb54928 100644 --- a/openstack/identity/v3/ec2tokens/requests.go +++ b/openstack/identity/v3/ec2tokens/requests.go @@ -300,8 +300,7 @@ func Create(ctx context.Context, c *gophercloud.ServiceClient, opts tokens.AuthO deleteBodyElements(b, "token") resp, err := c.Post(ctx, ec2tokensURL(c), b, &r.Body, &gophercloud.RequestOpts{ - MoreHeaders: map[string]string{"X-Auth-Token": ""}, - OkCodes: []int{200}, + OkCodes: []int{200}, }) _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return @@ -320,8 +319,7 @@ func ValidateS3Token(ctx context.Context, c *gophercloud.ServiceClient, opts tok deleteBodyElements(b, "body_hash", "headers", "host", "params", "path", "verb") resp, err := c.Post(ctx, s3tokensURL(c), b, &r.Body, &gophercloud.RequestOpts{ - MoreHeaders: map[string]string{"X-Auth-Token": ""}, - OkCodes: []int{200}, + OkCodes: []int{200}, }) _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return From 47c569100bef6786bb235ebc3b489fde440aa75c Mon Sep 17 00:00:00 2001 From: Winicius Silva Date: Thu, 13 Nov 2025 22:05:13 -0300 Subject: [PATCH 275/429] identity/services: add omitempty to the `type` field --- openstack/identity/v3/services/requests.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openstack/identity/v3/services/requests.go b/openstack/identity/v3/services/requests.go index c1e07908ad..8e8011da01 100644 --- a/openstack/identity/v3/services/requests.go +++ b/openstack/identity/v3/services/requests.go @@ -109,7 +109,7 @@ type UpdateOptsBuilder interface { // UpdateOpts provides options for updating a service. type UpdateOpts struct { // Type is the type of the service. - Type string `json:"type"` + Type string `json:"type,omitempty"` // Enabled is whether or not the service is enabled. Enabled *bool `json:"enabled,omitempty"` From 817b1b5f21629771cd95506c23791c00522b3d7b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Nov 2025 12:54:34 +0000 Subject: [PATCH 276/429] build(deps): bump golang.org/x/crypto from 0.43.0 to 0.44.0 Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.43.0 to 0.44.0. - [Commits](https://github.com/golang/crypto/compare/v0.43.0...v0.44.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-version: 0.44.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 033b59f3ec..e9f5b3d1ec 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module github.com/gophercloud/gophercloud/v2 go 1.24.0 require ( - golang.org/x/crypto v0.43.0 + golang.org/x/crypto v0.44.0 gopkg.in/yaml.v2 v2.4.0 ) -require golang.org/x/sys v0.37.0 // indirect +require golang.org/x/sys v0.38.0 // indirect diff --git a/go.sum b/go.sum index fc73315e9a..f61f4a7916 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ -golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= -golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= -golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= -golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= -golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= +golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU= +golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= +golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= From 41a23bb1deacd7527df3776103bee0bce4eaaf05 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Nov 2025 02:59:49 +0000 Subject: [PATCH 277/429] build(deps): bump golang.org/x/crypto from 0.44.0 to 0.45.0 Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.44.0 to 0.45.0. - [Commits](https://github.com/golang/crypto/compare/v0.44.0...v0.45.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-version: 0.45.0 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index e9f5b3d1ec..860326324b 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/gophercloud/gophercloud/v2 go 1.24.0 require ( - golang.org/x/crypto v0.44.0 + golang.org/x/crypto v0.45.0 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index f61f4a7916..8606f6d030 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU= -golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc= +golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= +golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= From 4daa3f4f9c69d102e9d376ac2bd6949408ff2d2f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Nov 2025 09:04:13 +0000 Subject: [PATCH 278/429] build(deps): bump actions/checkout from 5 to 6 Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql-analysis.yaml | 2 +- .github/workflows/ensure-labels.yaml | 2 +- .github/workflows/functional-baremetal.yaml | 2 +- .github/workflows/functional-basic.yaml | 2 +- .github/workflows/functional-blockstorage.yaml | 2 +- .github/workflows/functional-compute.yaml | 2 +- .github/workflows/functional-containerinfra.yaml | 2 +- .github/workflows/functional-dns.yaml | 2 +- .github/workflows/functional-fwaas_v2.yaml | 2 +- .github/workflows/functional-identity.yaml | 2 +- .github/workflows/functional-image.yaml | 2 +- .github/workflows/functional-keymanager.yaml | 2 +- .github/workflows/functional-loadbalancer.yaml | 2 +- .github/workflows/functional-messaging.yaml | 2 +- .github/workflows/functional-networking.yaml | 2 +- .github/workflows/functional-objectstorage.yaml | 2 +- .github/workflows/functional-orchestration.yaml | 2 +- .github/workflows/functional-placement.yaml | 2 +- .github/workflows/functional-sharedfilesystems.yaml | 2 +- .github/workflows/functional-workflow.yaml | 2 +- .github/workflows/label-pr.yaml | 2 +- .github/workflows/lint.yaml | 2 +- .github/workflows/unit.yaml | 2 +- 23 files changed, 23 insertions(+), 23 deletions(-) diff --git a/.github/workflows/codeql-analysis.yaml b/.github/workflows/codeql-analysis.yaml index 52619c3d30..90765a6eca 100644 --- a/.github/workflows/codeql-analysis.yaml +++ b/.github/workflows/codeql-analysis.yaml @@ -18,7 +18,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Setup Go uses: actions/setup-go@v6 diff --git a/.github/workflows/ensure-labels.yaml b/.github/workflows/ensure-labels.yaml index 3f8bd42cb2..907a7b8733 100644 --- a/.github/workflows/ensure-labels.yaml +++ b/.github/workflows/ensure-labels.yaml @@ -10,7 +10,7 @@ jobs: ensure: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: micnncim/action-label-syncer@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/functional-baremetal.yaml b/.github/workflows/functional-baremetal.yaml index d90653c08c..da24d3c8e6 100644 --- a/.github/workflows/functional-baremetal.yaml +++ b/.github/workflows/functional-baremetal.yaml @@ -23,7 +23,7 @@ jobs: name: Ironic on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-basic.yaml b/.github/workflows/functional-basic.yaml index 31df68c284..eacf51d7b6 100644 --- a/.github/workflows/functional-basic.yaml +++ b/.github/workflows/functional-basic.yaml @@ -23,7 +23,7 @@ jobs: name: basic tests on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-blockstorage.yaml b/.github/workflows/functional-blockstorage.yaml index 2e37c98529..e1b52375e2 100644 --- a/.github/workflows/functional-blockstorage.yaml +++ b/.github/workflows/functional-blockstorage.yaml @@ -23,7 +23,7 @@ jobs: name: Cinder on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-compute.yaml b/.github/workflows/functional-compute.yaml index 455a514a5b..e5b71f9a31 100644 --- a/.github/workflows/functional-compute.yaml +++ b/.github/workflows/functional-compute.yaml @@ -23,7 +23,7 @@ jobs: name: Nova on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-containerinfra.yaml b/.github/workflows/functional-containerinfra.yaml index ebfbbcf57f..cda8e1a93b 100644 --- a/.github/workflows/functional-containerinfra.yaml +++ b/.github/workflows/functional-containerinfra.yaml @@ -44,7 +44,7 @@ jobs: name: Magnum on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-dns.yaml b/.github/workflows/functional-dns.yaml index 8c9a837a15..05a9d0e0a9 100644 --- a/.github/workflows/functional-dns.yaml +++ b/.github/workflows/functional-dns.yaml @@ -29,7 +29,7 @@ jobs: name: Designate on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-fwaas_v2.yaml b/.github/workflows/functional-fwaas_v2.yaml index e9c8a4a34b..031a2f0554 100644 --- a/.github/workflows/functional-fwaas_v2.yaml +++ b/.github/workflows/functional-fwaas_v2.yaml @@ -27,7 +27,7 @@ jobs: name: FWaaS_v2 on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-identity.yaml b/.github/workflows/functional-identity.yaml index 381e1b79da..a9eb2ebdf2 100644 --- a/.github/workflows/functional-identity.yaml +++ b/.github/workflows/functional-identity.yaml @@ -23,7 +23,7 @@ jobs: name: Keystone on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-image.yaml b/.github/workflows/functional-image.yaml index 646d9f5f4e..68a3a5a952 100644 --- a/.github/workflows/functional-image.yaml +++ b/.github/workflows/functional-image.yaml @@ -23,7 +23,7 @@ jobs: name: Glance on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-keymanager.yaml b/.github/workflows/functional-keymanager.yaml index f573423523..65a336b8da 100644 --- a/.github/workflows/functional-keymanager.yaml +++ b/.github/workflows/functional-keymanager.yaml @@ -35,7 +35,7 @@ jobs: name: Barbican on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-loadbalancer.yaml b/.github/workflows/functional-loadbalancer.yaml index 2dad9a65bb..32a89fa38f 100644 --- a/.github/workflows/functional-loadbalancer.yaml +++ b/.github/workflows/functional-loadbalancer.yaml @@ -29,7 +29,7 @@ jobs: name: Octavia on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-messaging.yaml b/.github/workflows/functional-messaging.yaml index 80da8e09cc..3d3e91e788 100644 --- a/.github/workflows/functional-messaging.yaml +++ b/.github/workflows/functional-messaging.yaml @@ -23,7 +23,7 @@ jobs: name: Zaqar on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-networking.yaml b/.github/workflows/functional-networking.yaml index be1a694d81..0330136664 100644 --- a/.github/workflows/functional-networking.yaml +++ b/.github/workflows/functional-networking.yaml @@ -23,7 +23,7 @@ jobs: name: Neutron on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-objectstorage.yaml b/.github/workflows/functional-objectstorage.yaml index 118a0b14a9..c845ea9425 100644 --- a/.github/workflows/functional-objectstorage.yaml +++ b/.github/workflows/functional-objectstorage.yaml @@ -23,7 +23,7 @@ jobs: name: Swift on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-orchestration.yaml b/.github/workflows/functional-orchestration.yaml index 4c7f772d1e..310d626805 100644 --- a/.github/workflows/functional-orchestration.yaml +++ b/.github/workflows/functional-orchestration.yaml @@ -23,7 +23,7 @@ jobs: name: Heat on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-placement.yaml b/.github/workflows/functional-placement.yaml index eebbcc5091..6daa9ad097 100644 --- a/.github/workflows/functional-placement.yaml +++ b/.github/workflows/functional-placement.yaml @@ -23,7 +23,7 @@ jobs: name: Placement on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-sharedfilesystems.yaml b/.github/workflows/functional-sharedfilesystems.yaml index 17f7108f74..e0879e34b8 100644 --- a/.github/workflows/functional-sharedfilesystems.yaml +++ b/.github/workflows/functional-sharedfilesystems.yaml @@ -29,7 +29,7 @@ jobs: name: Manila on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-workflow.yaml b/.github/workflows/functional-workflow.yaml index df597a74f7..72fe6572ea 100644 --- a/.github/workflows/functional-workflow.yaml +++ b/.github/workflows/functional-workflow.yaml @@ -26,7 +26,7 @@ jobs: name: Mistral on Deploy OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/label-pr.yaml b/.github/workflows/label-pr.yaml index 8c7e9c55fa..d180b9207f 100644 --- a/.github/workflows/label-pr.yaml +++ b/.github/workflows/label-pr.yaml @@ -10,7 +10,7 @@ jobs: semver: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 with: fetch-depth: 0 ref: ${{ github.event.pull_request.head.sha }} diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 9c2d4787fa..3440a1e0c3 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Gophercloud - uses: actions/checkout@v5 + uses: actions/checkout@v6 - uses: actions/setup-go@v6 with: go-version: '1' diff --git a/.github/workflows/unit.yaml b/.github/workflows/unit.yaml index 4cda470c05..01d4ea6697 100644 --- a/.github/workflows/unit.yaml +++ b/.github/workflows/unit.yaml @@ -15,7 +15,7 @@ jobs: fail-fast: false steps: - name: Checkout Gophercloud - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Setup Go uses: actions/setup-go@v6 with: From a2037fab10c9d5defc3918f5cc18c755ff82a009 Mon Sep 17 00:00:00 2001 From: Winicius Silva Date: Wed, 26 Nov 2025 14:24:44 -0300 Subject: [PATCH 279/429] identity/service: add `name` and `description` fields --- openstack/identity/v3/services/requests.go | 12 ++++++ openstack/identity/v3/services/results.go | 19 ++++++++- .../v3/services/testing/fixtures_test.go | 40 +++++++++---------- .../v3/services/testing/requests_test.go | 19 +++++---- 4 files changed, 58 insertions(+), 32 deletions(-) diff --git a/openstack/identity/v3/services/requests.go b/openstack/identity/v3/services/requests.go index 8e8011da01..0a25c18179 100644 --- a/openstack/identity/v3/services/requests.go +++ b/openstack/identity/v3/services/requests.go @@ -15,6 +15,12 @@ type CreateOptsBuilder interface { // CreateOpts provides options used to create a service. type CreateOpts struct { + // Name is the name of the service. + Name string `json:"name,omitempty"` + + // Description is the description of the service. + Description string `json:"description,omitempty"` + // Type is the type of the service. Type string `json:"type"` @@ -108,6 +114,12 @@ type UpdateOptsBuilder interface { // UpdateOpts provides options for updating a service. type UpdateOpts struct { + // Name is an updated name for the service. + Name *string `json:"name,omitempty"` + + // Description is an update description for the service. + Description *string `json:"description,omitempty"` + // Type is the type of the service. Type string `json:"type,omitempty"` diff --git a/openstack/identity/v3/services/results.go b/openstack/identity/v3/services/results.go index 365e29b588..576370fc6d 100644 --- a/openstack/identity/v3/services/results.go +++ b/openstack/identity/v3/services/results.go @@ -50,6 +50,12 @@ type Service struct { // ID is the unique ID of the service. ID string `json:"id"` + // Name is the name of the service. + Name string `json:"name"` + + // Description is the description of the service. + Description string `json:"description"` + // Type is the type of the service. Type string `json:"type"` @@ -75,8 +81,6 @@ func (r *Service) UnmarshalJSON(b []byte) error { } *r = Service(s.tmp) - // Collect other fields and bundle them into Extra - // but only if a field titled "extra" wasn't sent. if s.Extra != nil { r.Extra = s.Extra } else { @@ -85,8 +89,19 @@ func (r *Service) UnmarshalJSON(b []byte) error { if err != nil { return err } + if resultMap, ok := result.(map[string]any); ok { r.Extra = gophercloud.RemainingKeys(Service{}, resultMap) + + // the following code is required for backward compatibility with the + // old behavior, when both description and name were in extra + if description, ok := resultMap["description"]; ok { + r.Extra["description"] = description + } + + if name, ok := resultMap["name"]; ok { + r.Extra["name"] = name + } } } diff --git a/openstack/identity/v3/services/testing/fixtures_test.go b/openstack/identity/v3/services/testing/fixtures_test.go index 9bd0076c58..42811a09d6 100644 --- a/openstack/identity/v3/services/testing/fixtures_test.go +++ b/openstack/identity/v3/services/testing/fixtures_test.go @@ -23,11 +23,11 @@ const ListOutput = ` "links": { "self": "https://example.com/identity/v3/services/1234" }, + "name": "service-one", "type": "identity", "enabled": false, "extra": { - "name": "service-one", - "description": "Service One" + "email": "service-one@example.com" } }, { @@ -35,11 +35,11 @@ const ListOutput = ` "links": { "self": "https://example.com/identity/v3/services/9876" }, + "name": "service-two", + "description": "Service Two", "type": "compute", "enabled": false, "extra": { - "name": "service-two", - "description": "Service Two", "email": "service@example.com" } } @@ -55,11 +55,11 @@ const GetOutput = ` "links": { "self": "https://example.com/identity/v3/services/9876" }, + "name": "service-two", + "description": "Service Two", "type": "compute", "enabled": false, "extra": { - "name": "service-two", - "description": "Service Two", "email": "service@example.com" } } @@ -96,11 +96,11 @@ const UpdateOutput = ` "links": { "self": "https://example.com/identity/v3/services/9876" }, + "name": "service-two", + "description": "Service Two Updated", "type": "compute2", "enabled": false, "extra": { - "name": "service-two", - "description": "Service Two Updated", "email": "service@example.com" } } @@ -113,11 +113,11 @@ var FirstService = services.Service{ Links: map[string]any{ "self": "https://example.com/identity/v3/services/1234", }, + Name: "service-one", Type: "identity", Enabled: false, Extra: map[string]any{ - "name": "service-one", - "description": "Service One", + "email": "service-one@example.com", }, } @@ -127,12 +127,12 @@ var SecondService = services.Service{ Links: map[string]any{ "self": "https://example.com/identity/v3/services/9876", }, - Type: "compute", - Enabled: false, + Name: "service-two", + Description: "Service Two", + Type: "compute", + Enabled: false, Extra: map[string]any{ - "name": "service-two", - "description": "Service Two", - "email": "service@example.com", + "email": "service@example.com", }, } @@ -142,12 +142,12 @@ var SecondServiceUpdated = services.Service{ Links: map[string]any{ "self": "https://example.com/identity/v3/services/9876", }, - Type: "compute2", - Enabled: false, + Name: "service-two", + Description: "Service Two Updated", + Type: "compute2", + Enabled: false, Extra: map[string]any{ - "name": "service-two", - "description": "Service Two Updated", - "email": "service@example.com", + "email": "service@example.com", }, } diff --git a/openstack/identity/v3/services/testing/requests_test.go b/openstack/identity/v3/services/testing/requests_test.go index 12c241ea9e..c88cefb322 100644 --- a/openstack/identity/v3/services/testing/requests_test.go +++ b/openstack/identity/v3/services/testing/requests_test.go @@ -17,11 +17,11 @@ func TestCreateSuccessful(t *testing.T) { HandleCreateServiceSuccessfully(t, fakeServer) createOpts := services.CreateOpts{ - Type: "compute", + Name: "service-two", + Description: "Service Two", + Type: "compute", Extra: map[string]any{ - "name": "service-two", - "description": "Service Two", - "email": "service@example.com", + "email": "service@example.com", }, } @@ -60,7 +60,7 @@ func TestListServicesAllPages(t *testing.T) { actual, err := services.ExtractServices(allPages) th.AssertNoErr(t, err) th.CheckDeepEquals(t, ExpectedServicesSlice, actual) - th.AssertEquals(t, ExpectedServicesSlice[0].Extra["name"], "service-one") + th.AssertEquals(t, ExpectedServicesSlice[0].Extra["email"], "service-one@example.com") th.AssertEquals(t, ExpectedServicesSlice[1].Extra["email"], "service@example.com") } @@ -81,16 +81,15 @@ func TestUpdateSuccessful(t *testing.T) { defer fakeServer.Teardown() HandleUpdateServiceSuccessfully(t, fakeServer) + updatedDescription := "Service Two Updated" updateOpts := services.UpdateOpts{ - Type: "compute2", - Extra: map[string]any{ - "description": "Service Two Updated", - }, + Description: &updatedDescription, + Type: "compute2", } actual, err := services.Update(context.TODO(), client.ServiceClient(fakeServer), "9876", updateOpts).Extract() th.AssertNoErr(t, err) th.CheckDeepEquals(t, SecondServiceUpdated, *actual) - th.AssertEquals(t, SecondServiceUpdated.Extra["description"], "Service Two Updated") + th.AssertEquals(t, SecondServiceUpdated.Description, "Service Two Updated") } func TestDeleteSuccessful(t *testing.T) { From f22d562c59aab9ff7585598eeea9bf7211751e38 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Dec 2025 09:02:48 +0000 Subject: [PATCH 280/429] build(deps): bump golang.org/x/crypto from 0.45.0 to 0.46.0 Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.45.0 to 0.46.0. - [Commits](https://github.com/golang/crypto/compare/v0.45.0...v0.46.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-version: 0.46.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 860326324b..91c175c962 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module github.com/gophercloud/gophercloud/v2 go 1.24.0 require ( - golang.org/x/crypto v0.45.0 + golang.org/x/crypto v0.46.0 gopkg.in/yaml.v2 v2.4.0 ) -require golang.org/x/sys v0.38.0 // indirect +require golang.org/x/sys v0.39.0 // indirect diff --git a/go.sum b/go.sum index 8606f6d030..03a132e602 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ -golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= -golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= -golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= From 603dd53722762343f6e628fb0752db29282e762a Mon Sep 17 00:00:00 2001 From: Winicius Silva Date: Wed, 10 Dec 2025 14:31:23 -0300 Subject: [PATCH 281/429] add: description field to identity.v3.Endpoint Signed-off-by: Winicius Silva --- openstack/identity/v3/endpoints/requests.go | 6 ++++ openstack/identity/v3/endpoints/results.go | 3 ++ .../v3/endpoints/testing/requests_test.go | 32 +++++++++++++------ 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/openstack/identity/v3/endpoints/requests.go b/openstack/identity/v3/endpoints/requests.go index 4386bb9bc9..4865d8861f 100644 --- a/openstack/identity/v3/endpoints/requests.go +++ b/openstack/identity/v3/endpoints/requests.go @@ -30,6 +30,9 @@ type CreateOpts struct { // ServiceID is the ID of the service the Endpoint refers to. ServiceID string `json:"service_id" required:"true"` + + // Description is the description of the Endpoint. + Description string `json:"description,omitempty"` } // ToEndpointCreateMap builds a request body from the Endpoint Create options. @@ -121,6 +124,9 @@ type UpdateOpts struct { // ServiceID is the ID of the service the Endpoint refers to. ServiceID string `json:"service_id,omitempty"` + + // Description is an updated description of the endpoint. + Description string `json:"description,omitempty"` } // ToEndpointUpdateMap builds an update request body from the Update options. diff --git a/openstack/identity/v3/endpoints/results.go b/openstack/identity/v3/endpoints/results.go index 19d279ebc6..7dbb1c9f7d 100644 --- a/openstack/identity/v3/endpoints/results.go +++ b/openstack/identity/v3/endpoints/results.go @@ -66,6 +66,9 @@ type Endpoint struct { // Enabled is whether or not the endpoint is enabled. Enabled bool `json:"enabled"` + + // Description is the description of the Endpoint. + Description string `json:"description"` } // EndpointPage is a single page of Endpoint results. diff --git a/openstack/identity/v3/endpoints/testing/requests_test.go b/openstack/identity/v3/endpoints/testing/requests_test.go index 7c418aed88..78991fe547 100644 --- a/openstack/identity/v3/endpoints/testing/requests_test.go +++ b/openstack/identity/v3/endpoints/testing/requests_test.go @@ -26,7 +26,8 @@ func TestCreateSuccessful(t *testing.T) { "name": "the-endiest-of-points", "region": "underground", "url": "https://1.2.3.4:9000/", - "service_id": "asdfasdfasdfasdf" + "service_id": "asdfasdfasdfasdf", + "description": "Test description" } }`) @@ -42,7 +43,8 @@ func TestCreateSuccessful(t *testing.T) { "name": "the-endiest-of-points", "region": "underground", "service_id": "asdfasdfasdfasdf", - "url": "https://1.2.3.4:9000/" + "url": "https://1.2.3.4:9000/", + "description": "Test description" } }`) }) @@ -53,6 +55,7 @@ func TestCreateSuccessful(t *testing.T) { Region: "underground", URL: "https://1.2.3.4:9000/", ServiceID: "asdfasdfasdfasdf", + Description: "Test description", }).Extract() th.AssertNoErr(t, err) @@ -64,6 +67,7 @@ func TestCreateSuccessful(t *testing.T) { Region: "underground", ServiceID: "asdfasdfasdfasdf", URL: "https://1.2.3.4:9000/", + Description: "Test description", } th.AssertDeepEquals(t, expected, actual) @@ -90,7 +94,8 @@ func TestListEndpoints(t *testing.T) { "name": "the-endiest-of-points", "region": "underground", "service_id": "asdfasdfasdfasdf", - "url": "https://1.2.3.4:9000/" + "url": "https://1.2.3.4:9000/", + "description": "List endpoint1 test" }, { "id": "13", @@ -102,7 +107,8 @@ func TestListEndpoints(t *testing.T) { "name": "shhhh", "region": "underground", "service_id": "asdfasdfasdfasdf", - "url": "https://1.2.3.4:9001/" + "url": "https://1.2.3.4:9001/", + "description": "List endpoint2 test" } ], "links": { @@ -130,6 +136,7 @@ func TestListEndpoints(t *testing.T) { Region: "underground", ServiceID: "asdfasdfasdfasdf", URL: "https://1.2.3.4:9000/", + Description: "List endpoint1 test", }, { ID: "13", @@ -139,6 +146,7 @@ func TestListEndpoints(t *testing.T) { Region: "underground", ServiceID: "asdfasdfasdfasdf", URL: "https://1.2.3.4:9001/", + Description: "List endpoint2 test", }, } th.AssertDeepEquals(t, expected, actual) @@ -167,7 +175,8 @@ func TestGetEndpoint(t *testing.T) { "name": "the-endiest-of-points", "region": "underground", "service_id": "asdfasdfasdfasdf", - "url": "https://1.2.3.4:9000/" + "url": "https://1.2.3.4:9000/", + "description": "Get endpoint test" } }`) }) @@ -185,6 +194,7 @@ func TestGetEndpoint(t *testing.T) { Region: "underground", ServiceID: "asdfasdfasdfasdf", URL: "https://1.2.3.4:9000/", + Description: "Get endpoint test", } th.AssertDeepEquals(t, expected, actual) } @@ -199,7 +209,8 @@ func TestUpdateEndpoint(t *testing.T) { th.TestJSONRequest(t, r, `{ "endpoint": { "name": "renamed", - "region": "somewhere-else" + "region": "somewhere-else", + "description": "Changed description" } }`) @@ -214,14 +225,16 @@ func TestUpdateEndpoint(t *testing.T) { "name": "renamed", "region": "somewhere-else", "service_id": "asdfasdfasdfasdf", - "url": "https://1.2.3.4:9000/" + "url": "https://1.2.3.4:9000/", + "description": "Changed description" } }`) }) actual, err := endpoints.Update(context.TODO(), client.ServiceClient(fakeServer), "12", endpoints.UpdateOpts{ - Name: "renamed", - Region: "somewhere-else", + Name: "renamed", + Region: "somewhere-else", + Description: "Changed description", }).Extract() if err != nil { t.Fatalf("Unexpected error from Update: %v", err) @@ -235,6 +248,7 @@ func TestUpdateEndpoint(t *testing.T) { Region: "somewhere-else", ServiceID: "asdfasdfasdfasdf", URL: "https://1.2.3.4:9000/", + Description: "Changed description", } th.AssertDeepEquals(t, expected, actual) } From c707541d489ca737b9fe97e8c16263f64fa9eb41 Mon Sep 17 00:00:00 2001 From: Winicius Silva Date: Thu, 11 Dec 2025 13:09:53 -0300 Subject: [PATCH 282/429] add: crud acceptance test for endpoint Signed-off-by: Winicius Silva --- .../openstack/identity/v3/endpoint_test.go | 36 +++++++++++++++ .../openstack/identity/v3/identity.go | 45 +++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/internal/acceptance/openstack/identity/v3/endpoint_test.go b/internal/acceptance/openstack/identity/v3/endpoint_test.go index 8dd9e5bad1..6f96adb981 100644 --- a/internal/acceptance/openstack/identity/v3/endpoint_test.go +++ b/internal/acceptance/openstack/identity/v3/endpoint_test.go @@ -100,3 +100,39 @@ func TestEndpointsNavigateCatalog(t *testing.T) { tools.PrintResource(t, allEndpoints[0]) } + +func TestEndpointCRUD(t *testing.T) { + clients.RequireAdmin(t) + + client, err := clients.NewIdentityV3Client() + th.AssertNoErr(t, err) + + service, err := CreateService(t, client, &services.CreateOpts{ + Type: "endpoint-test", + Name: tools.RandomString("ACPTTEST", 8), + Extra: map[string]any{}, + }) + th.AssertNoErr(t, err) + defer DeleteService(t, client, service.ID) + + endpoint, err := CreateEndpoint(t, client, &endpoints.CreateOpts{ + Availability: gophercloud.Availability("internal"), + ServiceID: service.ID, + URL: "https://example.com", + }) + th.AssertNoErr(t, err) + defer DeleteEndpoint(t, client, endpoint.ID) + + tools.PrintResource(t, endpoint) + tools.PrintResource(t, endpoint.URL) + + newEndpoint, err := endpoints.Update(context.TODO(), client, endpoint.ID, &endpoints.UpdateOpts{ + Name: "new-endpoint", + URL: "https://example-updated.com", + Description: "Updated Endpoint", + }).Extract() + th.AssertNoErr(t, err) + + th.AssertEquals(t, newEndpoint.URL, "https://example-updated.com") + th.AssertEquals(t, newEndpoint.Description, "Updated Endpoint") +} diff --git a/internal/acceptance/openstack/identity/v3/identity.go b/internal/acceptance/openstack/identity/v3/identity.go index ab34bb7530..a71c914430 100644 --- a/internal/acceptance/openstack/identity/v3/identity.go +++ b/internal/acceptance/openstack/identity/v3/identity.go @@ -7,6 +7,7 @@ import ( "github.com/gophercloud/gophercloud/v2" "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/domains" + "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/endpoints" "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/groups" "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/projects" "github.com/gophercloud/gophercloud/v2/openstack/identity/v3/regions" @@ -17,6 +18,38 @@ import ( th "github.com/gophercloud/gophercloud/v2/testhelper" ) +// CreateEndpoint will create an endpoint with a random name. It only define +// endpoint name and description, and receive from CreateOpts others parameters, +// such as URL, Availability and ServiceID. An error will be returned if the +// endpoint was unabled to be created. +func CreateEndpoint(t *testing.T, client *gophercloud.ServiceClient, c *endpoints.CreateOpts) (*endpoints.Endpoint, error) { + name := tools.RandomString("ACPTTEST", 8) + description := tools.RandomString("ACPTTEST-DESC", 8) + t.Logf("Attempting to create endpoint: %s", name) + + var createOpts endpoints.CreateOpts + if c != nil { + createOpts = *c + } else { + createOpts = endpoints.CreateOpts{} + } + + createOpts.Name = name + createOpts.Description = description + + endpoint, err := endpoints.Create(context.TODO(), client, createOpts).Extract() + if err != nil { + return endpoint, err + } + + t.Logf("Successfully created endpoint %s with ID %s", name, endpoint.ID) + + th.AssertEquals(t, endpoint.Name, name) + th.AssertEquals(t, endpoint.Description, description) + + return endpoint, nil +} + // CreateProject will create a project with a random name. // It takes an optional createOpts parameter since creating a project // has so many options. An error will be returned if the project was @@ -228,6 +261,18 @@ func CreateService(t *testing.T, client *gophercloud.ServiceClient, c *services. return service, nil } +// DeleteEndpoint will delete the specified Endpoint using its ID. A fatal error +// will occur if the endpoint failed to be deleted. This works best when using +// it as a deferred function. +func DeleteEndpoint(t *testing.T, client *gophercloud.ServiceClient, endpointID string) { + err := endpoints.Delete(context.TODO(), client, endpointID).ExtractErr() + if err != nil { + t.Fatalf("Unable to delete endpoint %s: %v", endpointID, err) + } + + t.Logf("Deleted endpoint: %s", endpointID) +} + // DeleteProject will delete a project by ID. A fatal error will occur if // the project ID failed to be deleted. This works best when using it as // a deferred function. From 9b8dcd512507ecc09662672ab0fe4b20aa103f0c Mon Sep 17 00:00:00 2001 From: Winicius Silva Date: Thu, 11 Dec 2025 23:32:15 -0300 Subject: [PATCH 283/429] add: support for update mac_address on port --- internal/acceptance/openstack/networking/v2/ports_test.go | 3 +++ openstack/networking/v2/ports/requests.go | 1 + openstack/networking/v2/ports/testing/fixtures.go | 5 +++-- openstack/networking/v2/ports/testing/requests_test.go | 4 ++++ 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/internal/acceptance/openstack/networking/v2/ports_test.go b/internal/acceptance/openstack/networking/v2/ports_test.go index 569beeebd4..f6ff48e829 100644 --- a/internal/acceptance/openstack/networking/v2/ports_test.go +++ b/internal/acceptance/openstack/networking/v2/ports_test.go @@ -45,9 +45,11 @@ func TestPortsCRUD(t *testing.T) { // Update port newPortName := "" newPortDescription := "" + newMACAddress := "aa:bb:cc:dd:ee:ff" updateOpts := ports.UpdateOpts{ Name: &newPortName, Description: &newPortDescription, + MACAddress: &newMACAddress, } newPort, err := ports.Update(context.TODO(), client, port.ID, updateOpts).Extract() th.AssertNoErr(t, err) @@ -56,6 +58,7 @@ func TestPortsCRUD(t *testing.T) { th.AssertEquals(t, newPort.Name, newPortName) th.AssertEquals(t, newPort.Description, newPortDescription) + th.AssertEquals(t, newPort.MACAddress, newMACAddress) allPages, err := ports.List(client, nil).AllPages(context.TODO()) th.AssertNoErr(t, err) diff --git a/openstack/networking/v2/ports/requests.go b/openstack/networking/v2/ports/requests.go index bfff2dffb2..a9c5c37535 100644 --- a/openstack/networking/v2/ports/requests.go +++ b/openstack/networking/v2/ports/requests.go @@ -197,6 +197,7 @@ type UpdateOpts struct { AllowedAddressPairs *[]AddressPair `json:"allowed_address_pairs,omitempty"` PropagateUplinkStatus *bool `json:"propagate_uplink_status,omitempty"` ValueSpecs *map[string]string `json:"value_specs,omitempty"` + MACAddress *string `json:"mac_address,omitempty"` // RevisionNumber implements extension:standard-attr-revisions. If != "" it // will set revision_number=%s. If the revision number does not match, the diff --git a/openstack/networking/v2/ports/testing/fixtures.go b/openstack/networking/v2/ports/testing/fixtures.go index b4c03fd618..b11650863f 100644 --- a/openstack/networking/v2/ports/testing/fixtures.go +++ b/openstack/networking/v2/ports/testing/fixtures.go @@ -409,7 +409,8 @@ const UpdateRequest = ` ], "security_groups": [ "f0ac4394-7e4a-4409-9701-ba8be283dbc3" - ] + ], + "mac_address": "fa:16:3e:c9:cb:f4" } } ` @@ -423,7 +424,7 @@ const UpdateResponse = ` "network_id": "a87cc70a-3e15-4acf-8205-9b711a3531b7", "tenant_id": "d6700c0c9ffa4f1cb322cd4a1f3906fa", "device_owner": "", - "mac_address": "fa:16:3e:c9:cb:f0", + "mac_address": "fa:16:3e:c9:cb:f4", "fixed_ips": [ { "subnet_id": "a0304c3a-4f08-4c43-88af-d796509c97d2", diff --git a/openstack/networking/v2/ports/testing/requests_test.go b/openstack/networking/v2/ports/testing/requests_test.go index ac1a2cd79a..f69962f74b 100644 --- a/openstack/networking/v2/ports/testing/requests_test.go +++ b/openstack/networking/v2/ports/testing/requests_test.go @@ -538,6 +538,7 @@ func TestUpdate(t *testing.T) { }) name := "new_port_name" + newMACAddress := "fa:16:3e:c9:cb:f4" options := ports.UpdateOpts{ Name: &name, FixedIPs: []ports.IP{ @@ -547,6 +548,7 @@ func TestUpdate(t *testing.T) { AllowedAddressPairs: &[]ports.AddressPair{ {IPAddress: "10.0.0.4", MACAddress: "fa:16:3e:c9:cb:f0"}, }, + MACAddress: &newMACAddress, } s, err := ports.Update(context.TODO(), fake.ServiceClient(fakeServer), "65c0ee9f-d634-4522-8954-51021b570b0d", options).Extract() @@ -727,6 +729,7 @@ func TestUpdateRevision(t *testing.T) { }) name := "new_port_name" + newMACAddress := "fa:16:3e:c9:cb:f4" options := ports.UpdateOpts{ Name: &name, FixedIPs: []ports.IP{ @@ -736,6 +739,7 @@ func TestUpdateRevision(t *testing.T) { AllowedAddressPairs: &[]ports.AddressPair{ {IPAddress: "10.0.0.4", MACAddress: "fa:16:3e:c9:cb:f0"}, }, + MACAddress: &newMACAddress, } _, err := ports.Update(context.TODO(), fake.ServiceClient(fakeServer), "65c0ee9f-d634-4522-8954-51021b570b0d", options).Extract() th.AssertNoErr(t, err) From c85676dca90f8cff1cb9c69bf7a3d2fff5daf09f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Dec 2025 09:04:01 +0000 Subject: [PATCH 284/429] build(deps): bump kiegroup/git-backporting from 4.8.6 to 4.8.7 Bumps [kiegroup/git-backporting](https://github.com/kiegroup/git-backporting) from 4.8.6 to 4.8.7. - [Release notes](https://github.com/kiegroup/git-backporting/releases) - [Changelog](https://github.com/kiegroup/git-backporting/blob/main/CHANGELOG.md) - [Commits](https://github.com/kiegroup/git-backporting/compare/7d895d030f5cf02f4a76c7f0bc79b41d8747b17c...baae3fe1e3c71bc6b1a2699b3bc1e153a19d5ac7) --- updated-dependencies: - dependency-name: kiegroup/git-backporting dependency-version: 4.8.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/backport.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/backport.yaml b/.github/workflows/backport.yaml index 86504701ea..04f06538ac 100644 --- a/.github/workflows/backport.yaml +++ b/.github/workflows/backport.yaml @@ -34,7 +34,7 @@ jobs: if: > contains(github.event.pull_request.labels.*.name, 'semver:patch') || contains(github.event.label.name, 'semver:patch') - uses: kiegroup/git-backporting@7d895d030f5cf02f4a76c7f0bc79b41d8747b17c + uses: kiegroup/git-backporting@baae3fe1e3c71bc6b1a2699b3bc1e153a19d5ac7 with: target-branch: v1 pull-request: ${{ github.event.pull_request.url }} @@ -97,7 +97,7 @@ jobs: || contains(github.event.pull_request.labels.*.name, 'semver:minor') || contains(github.event.label.name, 'semver:patch') || contains(github.event.label.name, 'semver:minor') - uses: kiegroup/git-backporting@7d895d030f5cf02f4a76c7f0bc79b41d8747b17c + uses: kiegroup/git-backporting@baae3fe1e3c71bc6b1a2699b3bc1e153a19d5ac7 with: target-branch: v2 pull-request: ${{ github.event.pull_request.url }} From 0119785a87742869e499b4477d7c352ecb9ca288 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?p=C3=BDrus?= Date: Thu, 11 Dec 2025 11:34:22 +0100 Subject: [PATCH 285/429] keystone: add support for per page limit --- openstack/identity/v3/domains/requests.go | 3 ++ openstack/identity/v3/projects/requests.go | 3 ++ .../v3/projects/testing/fixtures_test.go | 37 ++++++++++++++++++- .../v3/projects/testing/requests_test.go | 13 +++++-- 4 files changed, 51 insertions(+), 5 deletions(-) diff --git a/openstack/identity/v3/domains/requests.go b/openstack/identity/v3/domains/requests.go index 8ce72a9b33..94bb567f3c 100644 --- a/openstack/identity/v3/domains/requests.go +++ b/openstack/identity/v3/domains/requests.go @@ -20,6 +20,9 @@ type ListOpts struct { // Name filters the response by domain name. Name string `q:"name"` + + // Limit limits the number of projects returned per page. + Limit int `q:"limit"` } // ToDomainListQuery formats a ListOpts into a query string. diff --git a/openstack/identity/v3/projects/requests.go b/openstack/identity/v3/projects/requests.go index 6fb8448a9f..5aecc94d93 100644 --- a/openstack/identity/v3/projects/requests.go +++ b/openstack/identity/v3/projects/requests.go @@ -45,6 +45,9 @@ type ListOpts struct { // NotTagsAny filters on specific project tags. At least one of the tags must be absent for the project. NotTagsAny string `q:"not-tags-any"` + // Limit limits the number of projects returned per page. + Limit int `q:"limit"` + // Filters filters the response by custom filters such as // 'name__contains=foo' Filters map[string]string `q:"-"` diff --git a/openstack/identity/v3/projects/testing/fixtures_test.go b/openstack/identity/v3/projects/testing/fixtures_test.go index 5c97fc7dd3..5782fde87c 100644 --- a/openstack/identity/v3/projects/testing/fixtures_test.go +++ b/openstack/identity/v3/projects/testing/fixtures_test.go @@ -59,7 +59,19 @@ const ListOutput = ` "parent_id": null, "tags": ["Red", "Team"], "test": "old" - }, + } + ], + "links": { + "next": "%sprojects?limit=1&marker=1234", + "self": "%sprojects?limit=1", + "previous": null + } +} +` + +const ListOutputSecondPage = ` +{ + "projects": [ { "is_domain": false, "description": "The team that is blue", @@ -73,8 +85,21 @@ const ListOutput = ` } } ], + "links": { + "next": "%sprojects?limit=1&marker=9876", + "self": "%sprojects?limit=1&marker=1234", + "previous": null + } +} +` + +const ListOutputThirdPage = ` +{ + "projects": [ + ], "links": { "next": null, + "self": "%sprojects?limit=1&marker=9876", "previous": null } } @@ -299,7 +324,15 @@ func HandleListProjectsSuccessfully(t *testing.T, fakeServer th.FakeServer) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - fmt.Fprint(w, ListOutput) + + switch r.URL.Query().Get("marker") { + case "": + fmt.Fprintf(w, ListOutput, fakeServer.Endpoint(), fakeServer.Endpoint()) + case "1234": + fmt.Fprintf(w, ListOutputSecondPage, fakeServer.Endpoint(), fakeServer.Endpoint()) + case "9876": + fmt.Fprintf(w, ListOutputThirdPage, fakeServer.Endpoint()) + } }) } diff --git a/openstack/identity/v3/projects/testing/requests_test.go b/openstack/identity/v3/projects/testing/requests_test.go index 5ecc88e45d..ca5bebe454 100644 --- a/openstack/identity/v3/projects/testing/requests_test.go +++ b/openstack/identity/v3/projects/testing/requests_test.go @@ -35,19 +35,26 @@ func TestListProjects(t *testing.T) { defer fakeServer.Teardown() HandleListProjectsSuccessfully(t, fakeServer) + actualProjects := make([]projects.Project, 0, 2) count := 0 - err := projects.List(client.ServiceClient(fakeServer), nil).EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) { + opts := projects.ListOpts{ + Limit: 1, + } + err := projects.List(client.ServiceClient(fakeServer), opts).EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) { count++ actual, err := projects.ExtractProjects(page) th.AssertNoErr(t, err) - th.CheckDeepEquals(t, ExpectedProjectSlice, actual) + actualProjects = append(actualProjects, actual...) return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, count, 2) + + th.CheckEquals(t, len(actualProjects), 2) + th.CheckDeepEquals(t, ExpectedProjectSlice, actualProjects) } func TestListGroupsFiltersCheck(t *testing.T) { From a4ba89918de3ab04dd6ea972a15c44e46601a636 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 09:04:09 +0000 Subject: [PATCH 286/429] build(deps): bump actions/upload-artifact from 5 to 6 Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/functional-baremetal.yaml | 2 +- .github/workflows/functional-basic.yaml | 2 +- .github/workflows/functional-blockstorage.yaml | 2 +- .github/workflows/functional-compute.yaml | 2 +- .github/workflows/functional-containerinfra.yaml | 2 +- .github/workflows/functional-dns.yaml | 2 +- .github/workflows/functional-fwaas_v2.yaml | 2 +- .github/workflows/functional-identity.yaml | 2 +- .github/workflows/functional-image.yaml | 2 +- .github/workflows/functional-keymanager.yaml | 2 +- .github/workflows/functional-loadbalancer.yaml | 2 +- .github/workflows/functional-messaging.yaml | 2 +- .github/workflows/functional-networking.yaml | 2 +- .github/workflows/functional-objectstorage.yaml | 2 +- .github/workflows/functional-orchestration.yaml | 2 +- .github/workflows/functional-placement.yaml | 2 +- .github/workflows/functional-sharedfilesystems.yaml | 2 +- .github/workflows/functional-workflow.yaml | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/functional-baremetal.yaml b/.github/workflows/functional-baremetal.yaml index d90653c08c..e8c2d61fbb 100644 --- a/.github/workflows/functional-baremetal.yaml +++ b/.github/workflows/functional-baremetal.yaml @@ -119,7 +119,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: functional-baremetal-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-basic.yaml b/.github/workflows/functional-basic.yaml index 31df68c284..bf41ffc542 100644 --- a/.github/workflows/functional-basic.yaml +++ b/.github/workflows/functional-basic.yaml @@ -72,7 +72,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: functional-basic-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-blockstorage.yaml b/.github/workflows/functional-blockstorage.yaml index 2e37c98529..d03ccfa243 100644 --- a/.github/workflows/functional-blockstorage.yaml +++ b/.github/workflows/functional-blockstorage.yaml @@ -78,7 +78,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: functional-blockstorage-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-compute.yaml b/.github/workflows/functional-compute.yaml index 455a514a5b..c642399dff 100644 --- a/.github/workflows/functional-compute.yaml +++ b/.github/workflows/functional-compute.yaml @@ -78,7 +78,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: functional-compute-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-containerinfra.yaml b/.github/workflows/functional-containerinfra.yaml index ebfbbcf57f..528e8cb924 100644 --- a/.github/workflows/functional-containerinfra.yaml +++ b/.github/workflows/functional-containerinfra.yaml @@ -105,7 +105,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: functional-containerinfra-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-dns.yaml b/.github/workflows/functional-dns.yaml index 8c9a837a15..9992345007 100644 --- a/.github/workflows/functional-dns.yaml +++ b/.github/workflows/functional-dns.yaml @@ -86,7 +86,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: functional-dns-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-fwaas_v2.yaml b/.github/workflows/functional-fwaas_v2.yaml index e9c8a4a34b..57c02ef9e1 100644 --- a/.github/workflows/functional-fwaas_v2.yaml +++ b/.github/workflows/functional-fwaas_v2.yaml @@ -101,7 +101,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: functional-fwaas_v2-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-identity.yaml b/.github/workflows/functional-identity.yaml index 381e1b79da..eeda5e352f 100644 --- a/.github/workflows/functional-identity.yaml +++ b/.github/workflows/functional-identity.yaml @@ -76,7 +76,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: functional-identity-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-image.yaml b/.github/workflows/functional-image.yaml index 646d9f5f4e..859314ddd3 100644 --- a/.github/workflows/functional-image.yaml +++ b/.github/workflows/functional-image.yaml @@ -76,7 +76,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: functional-image-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-keymanager.yaml b/.github/workflows/functional-keymanager.yaml index f573423523..c9a86b210c 100644 --- a/.github/workflows/functional-keymanager.yaml +++ b/.github/workflows/functional-keymanager.yaml @@ -92,7 +92,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: functional-keymanager-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-loadbalancer.yaml b/.github/workflows/functional-loadbalancer.yaml index 2dad9a65bb..4534d92fe4 100644 --- a/.github/workflows/functional-loadbalancer.yaml +++ b/.github/workflows/functional-loadbalancer.yaml @@ -87,7 +87,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: functional-loadbalancer-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-messaging.yaml b/.github/workflows/functional-messaging.yaml index 80da8e09cc..69a5c3e1be 100644 --- a/.github/workflows/functional-messaging.yaml +++ b/.github/workflows/functional-messaging.yaml @@ -79,7 +79,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: functional-messaging-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-networking.yaml b/.github/workflows/functional-networking.yaml index be1a694d81..3167d54132 100644 --- a/.github/workflows/functional-networking.yaml +++ b/.github/workflows/functional-networking.yaml @@ -96,7 +96,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: functional-networking-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-objectstorage.yaml b/.github/workflows/functional-objectstorage.yaml index 118a0b14a9..a2b82391d3 100644 --- a/.github/workflows/functional-objectstorage.yaml +++ b/.github/workflows/functional-objectstorage.yaml @@ -82,7 +82,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: functional-objectstorage-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-orchestration.yaml b/.github/workflows/functional-orchestration.yaml index 4c7f772d1e..f2b2ce17c6 100644 --- a/.github/workflows/functional-orchestration.yaml +++ b/.github/workflows/functional-orchestration.yaml @@ -78,7 +78,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: functional-orchestration-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-placement.yaml b/.github/workflows/functional-placement.yaml index eebbcc5091..bd82762859 100644 --- a/.github/workflows/functional-placement.yaml +++ b/.github/workflows/functional-placement.yaml @@ -76,7 +76,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: functional-placement-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-sharedfilesystems.yaml b/.github/workflows/functional-sharedfilesystems.yaml index 17f7108f74..a1a492a156 100644 --- a/.github/workflows/functional-sharedfilesystems.yaml +++ b/.github/workflows/functional-sharedfilesystems.yaml @@ -100,7 +100,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: functional-sharedfilesystems-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-workflow.yaml b/.github/workflows/functional-workflow.yaml index df597a74f7..6c3f3a9822 100644 --- a/.github/workflows/functional-workflow.yaml +++ b/.github/workflows/functional-workflow.yaml @@ -81,7 +81,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: functional-workflow-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* From dd4071356bfc919b163f3a558701b1f630d2c367 Mon Sep 17 00:00:00 2001 From: eshulman2 Date: Thu, 11 Dec 2025 13:32:23 +0200 Subject: [PATCH 287/429] identity/v3/tokens: Add access rules support for application credentials This change adds support for the OpenStack-Identity-Access-Rules header when getting or validating tokens created with application credentials that have access rules configured. Changes: - Add GetOptsBuilder interface and GetOpts struct for Get() function - Add ValidateOptsBuilder interface and ValidateOpts struct for Validate() - Both structs contain AccessRulesVersion (float64) field to specify the header version. Pass nil to skip access rules validation, or provide opts with a version >= 1 to enable it. - Add float64 support to BuildHeaders() in params.go - Add AccessRule and ApplicationCredential types to represent the application credential information in token responses - Add ExtractApplicationCredential() method to extract application credential details including access rules from token responses - Update all usages across tests and client code The decision to use an opts struct pattern instead of passing the parameter directly was made to align with the rest of the gophercloud codebase conventions, although it may feel like overkill for a single optional parameter. This fixes the issue where tokens created with application credentials that have access rules would return 404 Not Found when fetched without the OpenStack-Identity-Access-Rules header. See: https://docs.openstack.org/keystone/latest/user/application_credentials.html Closes: #3573 assisted by: Claude --- internal/acceptance/openstack/client_test.go | 4 +- .../v3/applicationcredentials_test.go | 8 +- .../openstack/identity/v3/credentials_test.go | 8 +- .../openstack/identity/v3/oauth1_test.go | 2 +- .../openstack/identity/v3/token_test.go | 8 +- .../openstack/identity/v3/trusts_test.go | 2 +- openstack/client.go | 2 +- openstack/identity/v3/tokens/doc.go | 48 ++++++++++++ openstack/identity/v3/tokens/requests.go | 78 ++++++++++++++++--- openstack/identity/v3/tokens/results.go | 38 +++++++++ .../identity/v3/tokens/testing/fixtures.go | 70 +++++++++++++++++ .../v3/tokens/testing/requests_test.go | 78 ++++++++++++++++++- .../v3/tokens/testing/results_test.go | 20 +++++ 13 files changed, 334 insertions(+), 32 deletions(-) diff --git a/internal/acceptance/openstack/client_test.go b/internal/acceptance/openstack/client_test.go index 3a732d42ba..acb0399b11 100644 --- a/internal/acceptance/openstack/client_test.go +++ b/internal/acceptance/openstack/client_test.go @@ -71,11 +71,11 @@ func TestEC2AuthMethod(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, token) - user, err := tokens.Get(context.TODO(), client, token.ID).ExtractUser() + user, err := tokens.Get(context.TODO(), client, token.ID, nil).ExtractUser() th.AssertNoErr(t, err) tools.PrintResource(t, user) - project, err := tokens.Get(context.TODO(), client, token.ID).ExtractProject() + project, err := tokens.Get(context.TODO(), client, token.ID, nil).ExtractProject() th.AssertNoErr(t, err) tools.PrintResource(t, project) diff --git a/internal/acceptance/openstack/identity/v3/applicationcredentials_test.go b/internal/acceptance/openstack/identity/v3/applicationcredentials_test.go index 7a4ad01e1c..f8bb2ae129 100644 --- a/internal/acceptance/openstack/identity/v3/applicationcredentials_test.go +++ b/internal/acceptance/openstack/identity/v3/applicationcredentials_test.go @@ -50,15 +50,15 @@ func TestApplicationCredentialsCRD(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, token) - user, err := tokens.Get(context.TODO(), client, token.ID).ExtractUser() + user, err := tokens.Get(context.TODO(), client, token.ID, nil).ExtractUser() th.AssertNoErr(t, err) tools.PrintResource(t, user) - roles, err := tokens.Get(context.TODO(), client, token.ID).ExtractRoles() + roles, err := tokens.Get(context.TODO(), client, token.ID, nil).ExtractRoles() th.AssertNoErr(t, err) tools.PrintResource(t, roles) - project, err := tokens.Get(context.TODO(), client, token.ID).ExtractProject() + project, err := tokens.Get(context.TODO(), client, token.ID, nil).ExtractProject() th.AssertNoErr(t, err) tools.PrintResource(t, project) @@ -194,7 +194,7 @@ func TestApplicationCredentialsAccessRules(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, token) - user, err := tokens.Get(context.TODO(), client, token.ID).ExtractUser() + user, err := tokens.Get(context.TODO(), client, token.ID, nil).ExtractUser() th.AssertNoErr(t, err) tools.PrintResource(t, user) diff --git a/internal/acceptance/openstack/identity/v3/credentials_test.go b/internal/acceptance/openstack/identity/v3/credentials_test.go index ce0362abee..9590f41bff 100644 --- a/internal/acceptance/openstack/identity/v3/credentials_test.go +++ b/internal/acceptance/openstack/identity/v3/credentials_test.go @@ -39,11 +39,11 @@ func TestCredentialsCRUD(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, token) - user, err := tokens.Get(context.TODO(), client, token.ID).ExtractUser() + user, err := tokens.Get(context.TODO(), client, token.ID, nil).ExtractUser() th.AssertNoErr(t, err) tools.PrintResource(t, user) - project, err := tokens.Get(context.TODO(), client, token.ID).ExtractProject() + project, err := tokens.Get(context.TODO(), client, token.ID, nil).ExtractProject() th.AssertNoErr(t, err) tools.PrintResource(t, project) @@ -116,11 +116,11 @@ func TestCredentialsValidateS3(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, token) - user, err := tokens.Get(context.TODO(), client, token.ID).ExtractUser() + user, err := tokens.Get(context.TODO(), client, token.ID, nil).ExtractUser() th.AssertNoErr(t, err) tools.PrintResource(t, user) - project, err := tokens.Get(context.TODO(), client, token.ID).ExtractProject() + project, err := tokens.Get(context.TODO(), client, token.ID, nil).ExtractProject() th.AssertNoErr(t, err) tools.PrintResource(t, project) diff --git a/internal/acceptance/openstack/identity/v3/oauth1_test.go b/internal/acceptance/openstack/identity/v3/oauth1_test.go index 2e5b9b25fe..7a2ef800ab 100644 --- a/internal/acceptance/openstack/identity/v3/oauth1_test.go +++ b/internal/acceptance/openstack/identity/v3/oauth1_test.go @@ -215,7 +215,7 @@ func oauth1MethodTest(t *testing.T, client *gophercloud.ServiceClient, consumer tokens.Token oauth1.TokenExt } - tokenRes := tokens.Get(context.TODO(), newClient, newClient.TokenID) + tokenRes := tokens.Get(context.TODO(), newClient, newClient.TokenID, nil) err = tokenRes.ExtractInto(&token) th.AssertNoErr(t, err) oauth1Roles, err := tokenRes.ExtractRoles() diff --git a/internal/acceptance/openstack/identity/v3/token_test.go b/internal/acceptance/openstack/identity/v3/token_test.go index 1bc436caa7..290bce9474 100644 --- a/internal/acceptance/openstack/identity/v3/token_test.go +++ b/internal/acceptance/openstack/identity/v3/token_test.go @@ -40,19 +40,19 @@ func TestTokensGet(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, token) - catalog, err := tokens.Get(context.TODO(), client, token.ID).ExtractServiceCatalog() + catalog, err := tokens.Get(context.TODO(), client, token.ID, nil).ExtractServiceCatalog() th.AssertNoErr(t, err) tools.PrintResource(t, catalog) - user, err := tokens.Get(context.TODO(), client, token.ID).ExtractUser() + user, err := tokens.Get(context.TODO(), client, token.ID, nil).ExtractUser() th.AssertNoErr(t, err) tools.PrintResource(t, user) - roles, err := tokens.Get(context.TODO(), client, token.ID).ExtractRoles() + roles, err := tokens.Get(context.TODO(), client, token.ID, nil).ExtractRoles() th.AssertNoErr(t, err) tools.PrintResource(t, roles) - project, err := tokens.Get(context.TODO(), client, token.ID).ExtractProject() + project, err := tokens.Get(context.TODO(), client, token.ID, nil).ExtractProject() th.AssertNoErr(t, err) tools.PrintResource(t, project) } diff --git a/internal/acceptance/openstack/identity/v3/trusts_test.go b/internal/acceptance/openstack/identity/v3/trusts_test.go index 2eb659d55b..225e09d4b0 100644 --- a/internal/acceptance/openstack/identity/v3/trusts_test.go +++ b/internal/acceptance/openstack/identity/v3/trusts_test.go @@ -43,7 +43,7 @@ func TestTrustCRUD(t *testing.T) { token, err := tokens.Create(context.TODO(), client, &authOptions).Extract() th.AssertNoErr(t, err) - adminUser, err := tokens.Get(context.TODO(), client, token.ID).ExtractUser() + adminUser, err := tokens.Get(context.TODO(), client, token.ID, nil).ExtractUser() th.AssertNoErr(t, err) // Get the admin and member role IDs. diff --git a/openstack/client.go b/openstack/client.go index 2c81b27f3f..234f23eba2 100644 --- a/openstack/client.go +++ b/openstack/client.go @@ -206,7 +206,7 @@ func v3auth(ctx context.Context, client *gophercloud.ProviderClient, endpoint st } v3Client.SetToken(tokenID) - result := tokens3.Get(ctx, v3Client, tokenID) + result := tokens3.Get(ctx, v3Client, tokenID, nil) if result.Err != nil { return result.Err } diff --git a/openstack/identity/v3/tokens/doc.go b/openstack/identity/v3/tokens/doc.go index c711d0c28e..597d781dce 100644 --- a/openstack/identity/v3/tokens/doc.go +++ b/openstack/identity/v3/tokens/doc.go @@ -103,5 +103,53 @@ Example to Create a Token from a Username and Password with Project Name Scope if err != nil { panic(err) } + +Example to Get a Token + + token, err := tokens.Get(context.TODO(), identityClient, "token_id", nil).ExtractToken() + if err != nil { + panic(err) + } + +# Example to Get a Token Created with Application Credentials Access Rules + +When validating or retrieving tokens that were created using application +credentials with access rules, the OpenStack-Identity-Access-Rules header +must be sent. Without this header, Keystone will return a 404 Not Found error. + +See https://docs.openstack.org/keystone/latest/user/application_credentials.html + + getOpts := tokens.GetOpts{ + AccessRulesVersion: "1.0", + } + token, err := tokens.Get(context.TODO(), identityClient, "token_id", getOpts).ExtractToken() + if err != nil { + panic(err) + } + +Example to Validate a Token + + ok, err := tokens.Validate(context.TODO(), identityClient, "token_id", nil) + if err != nil { + panic(err) + } + + if ok { + fmt.Println("Token is valid") + } + +Example to Validate a Token Created with Application Credentials Access Rules + + validateOpts := tokens.ValidateOpts{ + AccessRulesVersion: "1.0", + } + ok, err := tokens.Validate(context.TODO(), identityClient, "token_id", validateOpts) + if err != nil { + panic(err) + } + + if ok { + fmt.Println("Token is valid") + } */ package tokens diff --git a/openstack/identity/v3/tokens/requests.go b/openstack/identity/v3/tokens/requests.go index fa8b925d04..40b41e44db 100644 --- a/openstack/identity/v3/tokens/requests.go +++ b/openstack/identity/v3/tokens/requests.go @@ -2,10 +2,13 @@ package tokens import ( "context" + "maps" "github.com/gophercloud/gophercloud/v2" ) +const xSubjectTokenHeader = "X-Subject-Token" + // Scope allows a created token to be limited to a specific domain or project. type Scope struct { ProjectID string @@ -118,12 +121,6 @@ func (opts *AuthOptions) ToTokenV3HeadersMap(map[string]any) (map[string]string, return nil, nil } -func subjectTokenHeaders(subjectToken string) map[string]string { - return map[string]string{ - "X-Subject-Token": subjectToken, - } -} - // Create authenticates and either generates a new token, or changes the Scope // of an existing token. func Create(ctx context.Context, c *gophercloud.ServiceClient, opts AuthOptionsBuilder) (r CreateResult) { @@ -146,20 +143,79 @@ func Create(ctx context.Context, c *gophercloud.ServiceClient, opts AuthOptionsB return } +// GetOptsBuilder allows extensions to add additional parameters to +// the Get request. +type GetOptsBuilder interface { + ToTokenGetParams() (map[string]string, error) +} + +// GetOpts provides options for the Get request. +type GetOpts struct { + // AccessRulesVersion specifies the OpenStack-Identity-Access-Rules header + // version. This is required when getting tokens that were created using + // application credentials with access rules. Versions less than 1 will cause + // Keystone to ignore access rules validation. + AccessRulesVersion string `h:"OpenStack-Identity-Access-Rules"` +} + +// ToTokenGetParams formats GetOpts into request headers. +func (opts GetOpts) ToTokenGetParams() (map[string]string, error) { + return gophercloud.BuildHeaders(opts) +} + // Get validates and retrieves information about another token. -func Get(ctx context.Context, c *gophercloud.ServiceClient, token string) (r GetResult) { +func Get(ctx context.Context, c *gophercloud.ServiceClient, token string, opts GetOptsBuilder) (r GetResult) { + h := map[string]string{xSubjectTokenHeader: token} + if opts != nil { + b, err := opts.ToTokenGetParams() + if err != nil { + r.Err = err + return + } + maps.Copy(h, b) + } + resp, err := c.Get(ctx, tokenURL(c), &r.Body, &gophercloud.RequestOpts{ - MoreHeaders: subjectTokenHeaders(token), + MoreHeaders: h, OkCodes: []int{200, 203}, }) _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return } +// ValidateOptsBuilder allows extensions to add additional parameters to +// the Validate request. +type ValidateOptsBuilder interface { + ToTokenValidateParams() (map[string]string, error) +} + +// ValidateOpts provides options for the Validate request. +type ValidateOpts struct { + // AccessRulesVersion specifies the OpenStack-Identity-Access-Rules header + // version. This is required when validating tokens that were created using + // application credentials with access rules. Versions less than 1 will cause + // Keystone to ignore access rules validation. + AccessRulesVersion string `h:"OpenStack-Identity-Access-Rules"` +} + +// ToTokenValidateParams formats ValidateOpts into request headers. +func (opts ValidateOpts) ToTokenValidateParams() (map[string]string, error) { + return gophercloud.BuildHeaders(opts) +} + // Validate determines if a specified token is valid or not. -func Validate(ctx context.Context, c *gophercloud.ServiceClient, token string) (bool, error) { +func Validate(ctx context.Context, c *gophercloud.ServiceClient, token string, opts ValidateOptsBuilder) (bool, error) { + h := map[string]string{xSubjectTokenHeader: token} + if opts != nil { + b, err := opts.ToTokenValidateParams() + if err != nil { + return false, err + } + maps.Copy(h, b) + } + resp, err := c.Head(ctx, tokenURL(c), &gophercloud.RequestOpts{ - MoreHeaders: subjectTokenHeaders(token), + MoreHeaders: h, OkCodes: []int{200, 204, 404}, }) if err != nil { @@ -172,7 +228,7 @@ func Validate(ctx context.Context, c *gophercloud.ServiceClient, token string) ( // Revoke immediately makes specified token invalid. func Revoke(ctx context.Context, c *gophercloud.ServiceClient, token string) (r RevokeResult) { resp, err := c.Delete(ctx, tokenURL(c), &gophercloud.RequestOpts{ - MoreHeaders: subjectTokenHeaders(token), + MoreHeaders: map[string]string{xSubjectTokenHeader: token}, }) _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return diff --git a/openstack/identity/v3/tokens/results.go b/openstack/identity/v3/tokens/results.go index bd61a9a67d..1ec1ce4001 100644 --- a/openstack/identity/v3/tokens/results.go +++ b/openstack/identity/v3/tokens/results.go @@ -88,6 +88,33 @@ type Trust struct { TrustorUserID TrustUser `json:"trustor_user"` } +// AccessRule represents an access rule for an application credential. +type AccessRule struct { + // The ID of the access rule. + ID string `json:"id"` + // The API path that the application credential is permitted to access. + Path string `json:"path"` + // The request method that the application credential is permitted to use + // for a given API endpoint. + Method string `json:"method"` + // The service type identifier for the service that the application + // credential is permitted to access. + Service string `json:"service"` +} + +// ApplicationCredential represents the application credential information +// included in a token when the token was created using an application credential. +type ApplicationCredential struct { + // The ID of the application credential. + ID string `json:"id"` + // The name of the application credential. + Name string `json:"name"` + // A flag indicating whether the application credential is restricted. + Restricted bool `json:"restricted"` + // A list of access rules for the application credential. + AccessRules []AccessRule `json:"access_rules"` +} + // commonResult is the response from a request. A commonResult has various // methods which can be used to extract different details about the result. type commonResult struct { @@ -181,6 +208,17 @@ func (r commonResult) ExtractTrust() (*Trust, error) { return s.Trust, err } +// ExtractApplicationCredential returns the ApplicationCredential that was used +// to create the token. This is only present when the token was created using +// an application credential. +func (r commonResult) ExtractApplicationCredential() (*ApplicationCredential, error) { + var s struct { + ApplicationCredential *ApplicationCredential `json:"application_credential"` + } + err := r.ExtractInto(&s) + return s.ApplicationCredential, err +} + // CreateResult is the response from a Create request. Use ExtractToken() // to interpret it as a Token, or ExtractServiceCatalog() to interpret it // as a service catalog. diff --git a/openstack/identity/v3/tokens/testing/fixtures.go b/openstack/identity/v3/tokens/testing/fixtures.go index 00797867c9..f0580521cd 100644 --- a/openstack/identity/v3/tokens/testing/fixtures.go +++ b/openstack/identity/v3/tokens/testing/fixtures.go @@ -323,3 +323,73 @@ func getGetDomainResult(t *testing.T) tokens.GetResult { th.AssertNoErr(t, err) return result } + +// ApplicationCredentialTokenOutput is a sample response to a Token call +// using application credentials with access rules. +const ApplicationCredentialTokenOutput = ` +{ + "token":{ + "methods":["application_credential"], + "expires_at":"2017-06-03T02:19:49.000000Z", + "user":{ + "domain":{ + "id":"default", + "name":"Default" + }, + "id":"0fe36e73809d46aeae6705c39077b1b3", + "name":"admin" + }, + "application_credential":{ + "id":"d832f05beee743c696672ef65ee073ff", + "name":"test", + "restricted":true, + "access_rules":[ + { + "id":"4641f614301d48bfae1ad323e3e1c44c", + "service":"identity", + "path":"/v3/auth/tokens", + "method":"GET" + }, + { + "id":"968c404cb9b44672a574e5ee9d3db987", + "service":"identity", + "path":"/v3/**", + "method":"HEAD" + } + ] + }, + "issued_at":"2017-06-03T01:19:49.000000Z" + } +}` + +// ExpectedApplicationCredential contains expected application credential +// extracted from token response. +var ExpectedApplicationCredential = tokens.ApplicationCredential{ + ID: "d832f05beee743c696672ef65ee073ff", + Name: "test", + Restricted: true, + AccessRules: []tokens.AccessRule{ + { + ID: "4641f614301d48bfae1ad323e3e1c44c", + Service: "identity", + Path: "/v3/auth/tokens", + Method: "GET", + }, + { + ID: "968c404cb9b44672a574e5ee9d3db987", + Service: "identity", + Path: "/v3/**", + Method: "HEAD", + }, + }, +} + +func getGetApplicationCredentialResult(t *testing.T) tokens.GetResult { + result := tokens.GetResult{} + result.Header = http.Header{ + "X-Subject-Token": []string{testTokenID}, + } + err := json.Unmarshal([]byte(ApplicationCredentialTokenOutput), &result.Body) + th.AssertNoErr(t, err) + return result +} diff --git a/openstack/identity/v3/tokens/testing/requests_test.go b/openstack/identity/v3/tokens/testing/requests_test.go index 8157de3ca7..c8c5d49805 100644 --- a/openstack/identity/v3/tokens/testing/requests_test.go +++ b/openstack/identity/v3/tokens/testing/requests_test.go @@ -675,7 +675,7 @@ func TestGetRequest(t *testing.T) { `) }) - token, err := tokens.Get(context.TODO(), &client, "abcdef12345").Extract() + token, err := tokens.Get(context.TODO(), &client, "abcdef12345", nil).Extract() if err != nil { t.Errorf("Info returned an error: %v", err) } @@ -712,7 +712,7 @@ func TestValidateRequestSuccessful(t *testing.T) { defer fakeServer.Teardown() client := prepareAuthTokenHandler(t, fakeServer, "HEAD", http.StatusNoContent) - ok, err := tokens.Validate(context.TODO(), &client, "abcdef12345") + ok, err := tokens.Validate(context.TODO(), &client, "abcdef12345", nil) if err != nil { t.Errorf("Unexpected error from Validate: %v", err) } @@ -727,7 +727,7 @@ func TestValidateRequestFailure(t *testing.T) { defer fakeServer.Teardown() client := prepareAuthTokenHandler(t, fakeServer, "HEAD", http.StatusNotFound) - ok, err := tokens.Validate(context.TODO(), &client, "abcdef12345") + ok, err := tokens.Validate(context.TODO(), &client, "abcdef12345", nil) if err != nil { t.Errorf("Unexpected error from Validate: %v", err) } @@ -742,7 +742,7 @@ func TestValidateRequestError(t *testing.T) { defer fakeServer.Teardown() client := prepareAuthTokenHandler(t, fakeServer, "HEAD", http.StatusMethodNotAllowed) - _, err := tokens.Validate(context.TODO(), &client, "abcdef12345") + _, err := tokens.Validate(context.TODO(), &client, "abcdef12345", nil) if err == nil { t.Errorf("Missing expected error from Validate") } @@ -768,6 +768,76 @@ func TestRevokeRequestError(t *testing.T) { } } +func TestGetRequestWithAccessRules(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + client := gophercloud.ServiceClient{ + ProviderClient: &gophercloud.ProviderClient{ + TokenID: "12345abcdef", + }, + Endpoint: fakeServer.Endpoint(), + } + + fakeServer.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", "12345abcdef") + th.TestHeader(t, r, "X-Subject-Token", "abcdef12345") + th.TestHeader(t, r, "OpenStack-Identity-Access-Rules", "1") + + w.WriteHeader(http.StatusOK) + fmt.Fprint(w, ` + { "token": { "expires_at": "2014-08-29T13:10:01.000000Z" } } + `) + }) + + getOpts := tokens.GetOpts{ + AccessRulesVersion: "1", + } + token, err := tokens.Get(context.TODO(), &client, "abcdef12345", getOpts).Extract() + if err != nil { + t.Errorf("Get returned an error: %v", err) + } + + expected, _ := time.Parse(time.UnixDate, "Fri Aug 29 13:10:01 UTC 2014") + if token.ExpiresAt != expected { + t.Errorf("Expected expiration time %s, but was %s", expected.Format(time.UnixDate), time.Time(token.ExpiresAt).Format(time.UnixDate)) + } +} + +func TestValidateRequestWithAccessRules(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + client := gophercloud.ServiceClient{ + ProviderClient: &gophercloud.ProviderClient{ + TokenID: "12345abcdef", + }, + Endpoint: fakeServer.Endpoint(), + } + + fakeServer.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "HEAD") + th.TestHeader(t, r, "X-Auth-Token", "12345abcdef") + th.TestHeader(t, r, "X-Subject-Token", "abcdef12345") + th.TestHeader(t, r, "OpenStack-Identity-Access-Rules", "1") + + w.WriteHeader(http.StatusNoContent) + }) + + validateOpts := tokens.ValidateOpts{ + AccessRulesVersion: "1", + } + ok, err := tokens.Validate(context.TODO(), &client, "abcdef12345", validateOpts) + if err != nil { + t.Errorf("Unexpected error from Validate: %v", err) + } + + if !ok { + t.Errorf("Validate returned false for a valid token") + } +} + func TestNoTokenInResponse(t *testing.T) { fakeServer := th.SetupHTTP() defer fakeServer.Teardown() diff --git a/openstack/identity/v3/tokens/testing/results_test.go b/openstack/identity/v3/tokens/testing/results_test.go index c45581ffde..f5e4029c23 100644 --- a/openstack/identity/v3/tokens/testing/results_test.go +++ b/openstack/identity/v3/tokens/testing/results_test.go @@ -59,3 +59,23 @@ func TestExtractDomain(t *testing.T) { th.CheckDeepEquals(t, &ExpectedDomain, domain) } + +func TestExtractApplicationCredential(t *testing.T) { + result := getGetApplicationCredentialResult(t) + + appCred, err := result.ExtractApplicationCredential() + th.AssertNoErr(t, err) + + th.CheckDeepEquals(t, &ExpectedApplicationCredential, appCred) +} + +func TestExtractApplicationCredentialNotPresent(t *testing.T) { + result := getGetResult(t) + + appCred, err := result.ExtractApplicationCredential() + th.AssertNoErr(t, err) + + if appCred != nil { + t.Errorf("Expected nil application credential, got %v", appCred) + } +} From eb55a4f54774f0b7e28b6352b7d914d0b3b136a8 Mon Sep 17 00:00:00 2001 From: Winicius Silva Date: Mon, 15 Dec 2025 18:55:15 -0300 Subject: [PATCH 288/429] identity.v3.Endpoint: add enabled field on creation and on update --- .../openstack/identity/v3/endpoint_test.go | 4 ++++ openstack/identity/v3/endpoints/requests.go | 14 +++++++++++--- .../v3/endpoints/testing/requests_test.go | 18 ++++++++++++------ 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/internal/acceptance/openstack/identity/v3/endpoint_test.go b/internal/acceptance/openstack/identity/v3/endpoint_test.go index 6f96adb981..7d9da99854 100644 --- a/internal/acceptance/openstack/identity/v3/endpoint_test.go +++ b/internal/acceptance/openstack/identity/v3/endpoint_test.go @@ -115,10 +115,12 @@ func TestEndpointCRUD(t *testing.T) { th.AssertNoErr(t, err) defer DeleteService(t, client, service.ID) + enabled := false endpoint, err := CreateEndpoint(t, client, &endpoints.CreateOpts{ Availability: gophercloud.Availability("internal"), ServiceID: service.ID, URL: "https://example.com", + Enabled: &enabled, }) th.AssertNoErr(t, err) defer DeleteEndpoint(t, client, endpoint.ID) @@ -126,10 +128,12 @@ func TestEndpointCRUD(t *testing.T) { tools.PrintResource(t, endpoint) tools.PrintResource(t, endpoint.URL) + enabled = true newEndpoint, err := endpoints.Update(context.TODO(), client, endpoint.ID, &endpoints.UpdateOpts{ Name: "new-endpoint", URL: "https://example-updated.com", Description: "Updated Endpoint", + Enabled: &enabled, }).Extract() th.AssertNoErr(t, err) diff --git a/openstack/identity/v3/endpoints/requests.go b/openstack/identity/v3/endpoints/requests.go index 4865d8861f..45893aa3c6 100644 --- a/openstack/identity/v3/endpoints/requests.go +++ b/openstack/identity/v3/endpoints/requests.go @@ -18,6 +18,13 @@ type CreateOpts struct { // or public), referenced by the gophercloud.Availability type. Availability gophercloud.Availability `json:"interface" required:"true"` + // Description is the description of the Endpoint. + Description string `json:"description,omitempty"` + + // Enabled indicates whether the Endpoint appears in the service + // or not. + Enabled *bool `json:"enabled,omitempty"` + // Name is the name of the Endpoint. Name string `json:"name" required:"true"` @@ -30,9 +37,6 @@ type CreateOpts struct { // ServiceID is the ID of the service the Endpoint refers to. ServiceID string `json:"service_id" required:"true"` - - // Description is the description of the Endpoint. - Description string `json:"description,omitempty"` } // ToEndpointCreateMap builds a request body from the Endpoint Create options. @@ -115,6 +119,10 @@ type UpdateOpts struct { // Name is the name of the Endpoint. Name string `json:"name,omitempty"` + // Enabled indicates whether the Endpoint appears in the service + // or not. + Enabled *bool `json:"enabled,omitempty"` + // Region is the region the Endpoint is located in. // This field can be omitted or left as a blank string. Region string `json:"region,omitempty"` diff --git a/openstack/identity/v3/endpoints/testing/requests_test.go b/openstack/identity/v3/endpoints/testing/requests_test.go index 78991fe547..07798947c6 100644 --- a/openstack/identity/v3/endpoints/testing/requests_test.go +++ b/openstack/identity/v3/endpoints/testing/requests_test.go @@ -27,7 +27,8 @@ func TestCreateSuccessful(t *testing.T) { "region": "underground", "url": "https://1.2.3.4:9000/", "service_id": "asdfasdfasdfasdf", - "description": "Test description" + "description": "Test description", + "enabled": false } }`) @@ -36,7 +37,7 @@ func TestCreateSuccessful(t *testing.T) { "endpoint": { "id": "12", "interface": "public", - "enabled": true, + "enabled": false, "links": { "self": "https://localhost:5000/v3/endpoints/12" }, @@ -49,6 +50,7 @@ func TestCreateSuccessful(t *testing.T) { }`) }) + enabled := false actual, err := endpoints.Create(context.TODO(), client.ServiceClient(fakeServer), endpoints.CreateOpts{ Availability: gophercloud.AvailabilityPublic, Name: "the-endiest-of-points", @@ -56,14 +58,15 @@ func TestCreateSuccessful(t *testing.T) { URL: "https://1.2.3.4:9000/", ServiceID: "asdfasdfasdfasdf", Description: "Test description", + Enabled: &enabled, }).Extract() th.AssertNoErr(t, err) expected := &endpoints.Endpoint{ ID: "12", Availability: gophercloud.AvailabilityPublic, - Enabled: true, Name: "the-endiest-of-points", + Enabled: false, Region: "underground", ServiceID: "asdfasdfasdfasdf", URL: "https://1.2.3.4:9000/", @@ -210,7 +213,8 @@ func TestUpdateEndpoint(t *testing.T) { "endpoint": { "name": "renamed", "region": "somewhere-else", - "description": "Changed description" + "description": "Changed description", + "enabled": false } }`) @@ -218,7 +222,7 @@ func TestUpdateEndpoint(t *testing.T) { "endpoint": { "id": "12", "interface": "public", - "enabled": true, + "enabled": false, "links": { "self": "https://localhost:5000/v3/endpoints/12" }, @@ -231,10 +235,12 @@ func TestUpdateEndpoint(t *testing.T) { }`) }) + enabled := false actual, err := endpoints.Update(context.TODO(), client.ServiceClient(fakeServer), "12", endpoints.UpdateOpts{ Name: "renamed", Region: "somewhere-else", Description: "Changed description", + Enabled: &enabled, }).Extract() if err != nil { t.Fatalf("Unexpected error from Update: %v", err) @@ -243,7 +249,7 @@ func TestUpdateEndpoint(t *testing.T) { expected := &endpoints.Endpoint{ ID: "12", Availability: gophercloud.AvailabilityPublic, - Enabled: true, + Enabled: false, Name: "renamed", Region: "somewhere-else", ServiceID: "asdfasdfasdfasdf", From 9c2ed1136a45fcbf960aad2aade81a1843a1c085 Mon Sep 17 00:00:00 2001 From: Konstantin Eremin Date: Mon, 17 Nov 2025 08:51:08 +0300 Subject: [PATCH 289/429] Add new fields for ListOpts volumetypes Added fields: name, description, extra_specs Added tests --- .../blockstorage/v3/volumetypes/requests.go | 8 ++ .../v3/volumetypes/testing/requests_test.go | 92 +++++++++++++++++++ 2 files changed, 100 insertions(+) diff --git a/openstack/blockstorage/v3/volumetypes/requests.go b/openstack/blockstorage/v3/volumetypes/requests.go index 8849c394fb..ca8c8be754 100644 --- a/openstack/blockstorage/v3/volumetypes/requests.go +++ b/openstack/blockstorage/v3/volumetypes/requests.go @@ -73,9 +73,17 @@ type ListOptsBuilder interface { // ListOpts holds options for listing Volume Types. It is passed to the volumetypes.List // function. type ListOpts struct { + // Name will filter by the specified volume type name. + Name string `q:"name"` + // Description will filter by the specified volume type description. + Description string `q:"description"` // Specifies whether the query should include public or private Volume Types. // By default, it queries both types. IsPublic visibility `q:"is_public"` + // ExtraSpecs will filter results based on specified extra specs. + // The map key is the extra spec name, and the value is the filter value. + // For example: map[string]string{"multiattach": " True", "storage_protocol": "nfs"} + ExtraSpecs map[string]string `q:"extra_specs"` // Comma-separated list of sort keys and optional sort directions in the // form of [:]. Sort string `q:"sort"` diff --git a/openstack/blockstorage/v3/volumetypes/testing/requests_test.go b/openstack/blockstorage/v3/volumetypes/testing/requests_test.go index 2ed84d144e..4e21506a62 100644 --- a/openstack/blockstorage/v3/volumetypes/testing/requests_test.go +++ b/openstack/blockstorage/v3/volumetypes/testing/requests_test.go @@ -162,6 +162,98 @@ func TestListIsPublicParam(t *testing.T) { th.AssertNoErr(t, err) } +func TestListNameParam(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + result := make(map[string]string) + HandleListIsPublicParam(t, fakeServer, result) + + // Test with name filter + result["is_public"] = "None" + result["name"] = "test-type" + err := volumetypes.List(client.ServiceClient(fakeServer), volumetypes.ListOpts{ + Name: "test-type", + }).EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) { + return true, nil + }) + th.AssertNoErr(t, err) + + // Test with name, description, is_public, and extra_specs together + result["is_public"] = "true" + result["name"] = "test-type" + result["description"] = "test" + result["extra_specs"] = "{'storage_protocol':'nfs'}" + err = volumetypes.List(client.ServiceClient(fakeServer), volumetypes.ListOpts{ + Name: "test-type", + Description: "test", + IsPublic: volumetypes.VisibilityPublic, + ExtraSpecs: map[string]string{"storage_protocol": "nfs"}, + }).EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) { + return true, nil + }) + th.AssertNoErr(t, err) +} + +func TestListDescriptionParam(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + result := make(map[string]string) + HandleListIsPublicParam(t, fakeServer, result) + + // Test with description filter + result["is_public"] = "None" + result["description"] = "test" + err := volumetypes.List(client.ServiceClient(fakeServer), volumetypes.ListOpts{ + Description: "test", + }).EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) { + return true, nil + }) + th.AssertNoErr(t, err) + + // Test with description, is_public, and extra_specs together + result["is_public"] = "true" + result["description"] = "test" + result["extra_specs"] = "{'multiattach':' True'}" + err = volumetypes.List(client.ServiceClient(fakeServer), volumetypes.ListOpts{ + Description: "test", + IsPublic: volumetypes.VisibilityPublic, + ExtraSpecs: map[string]string{"multiattach": " True"}, + }).EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) { + return true, nil + }) + th.AssertNoErr(t, err) +} + +func TestListExtraSpecsParam(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + result := make(map[string]string) + HandleListIsPublicParam(t, fakeServer, result) + + // Test with extra_specs filter + result["is_public"] = "None" + result["extra_specs"] = "{'storage_protocol':'nfs'}" + err := volumetypes.List(client.ServiceClient(fakeServer), volumetypes.ListOpts{ + ExtraSpecs: map[string]string{"storage_protocol": "nfs"}, + }).EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) { + return true, nil + }) + th.AssertNoErr(t, err) + + // Test with multiple extra_specs + result["extra_specs"] = "{'multiattach':' True', 'replication_enabled':' True', 'RESKEY:availability_zones':'zone'}" + err = volumetypes.List(client.ServiceClient(fakeServer), volumetypes.ListOpts{ + ExtraSpecs: map[string]string{ + "multiattach": " True", + "replication_enabled": " True", + "RESKEY:availability_zones": "zone", + }, + }).EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) { + return true, nil + }) + th.AssertNoErr(t, err) +} + func TestVolumeTypeExtraSpecsList(t *testing.T) { fakeServer := th.SetupHTTP() defer fakeServer.Teardown() From bcdc1d97376776acc5378d4d0bcfa5ace0367444 Mon Sep 17 00:00:00 2001 From: Konstantin Eremin Date: Thu, 18 Dec 2025 00:31:52 +0300 Subject: [PATCH 290/429] Add tests --- .../v3/volumetypes/testing/fixtures_test.go | 120 ++++++++++++++++++ .../v3/volumetypes/testing/requests_test.go | 98 +++++++------- 2 files changed, 169 insertions(+), 49 deletions(-) diff --git a/openstack/blockstorage/v3/volumetypes/testing/fixtures_test.go b/openstack/blockstorage/v3/volumetypes/testing/fixtures_test.go index a03209f199..af09e18086 100644 --- a/openstack/blockstorage/v3/volumetypes/testing/fixtures_test.go +++ b/openstack/blockstorage/v3/volumetypes/testing/fixtures_test.go @@ -207,6 +207,126 @@ func HandleListIsPublicParam(t *testing.T, fakeServer th.FakeServer, values map[ }) } +func HandleListWithNameFilter(t *testing.T, fakeServer th.FakeServer, values map[string]string) { + fakeServer.Mux.HandleFunc("/types", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.TestFormValues(t, r, values) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + fmt.Fprint(w, ` +{ + "volume_types": [ + { + "name": "test-type", + "qos_specs_id": null, + "os-volume-type-access:is_public": true, + "extra_specs": { + "storage_protocol": "nfs" + }, + "is_public": true, + "id": "996af3df-92fd-4814-a0ee-ba5f899aa1ec", + "description": "test" + } + ] +} +`) + }) +} + +func HandleListWithDescriptionFilter(t *testing.T, fakeServer th.FakeServer, values map[string]string) { + fakeServer.Mux.HandleFunc("/types", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.TestFormValues(t, r, values) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + fmt.Fprint(w, ` +{ + "volume_types": [ + { + "name": "test-type", + "qos_specs_id": null, + "os-volume-type-access:is_public": true, + "extra_specs": { + "multiattach": " True" + }, + "is_public": true, + "id": "ab948f0a-13ed-47c8-b9be-cade0beb0706", + "description": "test" + } + ] +} +`) + }) +} + +func HandleListWithExtraSpecsFilter(t *testing.T, fakeServer th.FakeServer, values map[string]string) { + fakeServer.Mux.HandleFunc("/types", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.TestFormValues(t, r, values) + + if err := r.ParseForm(); err != nil { + t.Errorf("Failed to parse request form %v", err) + } + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + extraSpecsFilter := r.Form.Get("extra_specs") + + // Determine which volume type to return based on extra_specs filter + switch extraSpecsFilter { + case "{'storage_protocol':'nfs'}": + // Return only nfs-type + fmt.Fprint(w, ` +{ + "volume_types": [ + { + "name": "nfs-type", + "qos_specs_id": null, + "os-volume-type-access:is_public": true, + "extra_specs": { + "storage_protocol": "nfs" + }, + "is_public": true, + "id": "6b0cfee7-48b6-41b7-9d68-0d74cbdc08de", + "description": "NFS storage type" + } + ] +} +`) + case "{'multiattach':' True', 'replication_enabled':' True', 'RESKEY:availability_zones':'zone'}": + // Return only multiattach-type + fmt.Fprint(w, ` +{ + "volume_types": [ + { + "name": "multiattach-type", + "qos_specs_id": null, + "os-volume-type-access:is_public": true, + "extra_specs": { + "multiattach": " True", + "replication_enabled": " True", + "RESKEY:availability_zones": "zone" + }, + "is_public": true, + "id": "e1fc0553-0357-4206-af30-23137ee5f743", + "description": "Multiattach volume type" + } + ] +} +`) + default: + // Default: return empty list + fmt.Fprint(w, `{"volume_types": []}`) + } + }) +} + func HandleExtraSpecsListSuccessfully(t *testing.T, fakeServer th.FakeServer) { fakeServer.Mux.HandleFunc("/types/1/extra_specs", func(w http.ResponseWriter, r *http.Request) { th.TestMethod(t, r, "GET") diff --git a/openstack/blockstorage/v3/volumetypes/testing/requests_test.go b/openstack/blockstorage/v3/volumetypes/testing/requests_test.go index 4e21506a62..83b9ecd7fb 100644 --- a/openstack/blockstorage/v3/volumetypes/testing/requests_test.go +++ b/openstack/blockstorage/v3/volumetypes/testing/requests_test.go @@ -166,92 +166,92 @@ func TestListNameParam(t *testing.T) { fakeServer := th.SetupHTTP() defer fakeServer.Teardown() result := make(map[string]string) - HandleListIsPublicParam(t, fakeServer, result) + HandleListWithNameFilter(t, fakeServer, result) - // Test with name filter result["is_public"] = "None" result["name"] = "test-type" - err := volumetypes.List(client.ServiceClient(fakeServer), volumetypes.ListOpts{ + allPages, err := volumetypes.List(client.ServiceClient(fakeServer), volumetypes.ListOpts{ Name: "test-type", - }).EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) { - return true, nil - }) + }).AllPages(context.TODO()) th.AssertNoErr(t, err) - - // Test with name, description, is_public, and extra_specs together - result["is_public"] = "true" - result["name"] = "test-type" - result["description"] = "test" - result["extra_specs"] = "{'storage_protocol':'nfs'}" - err = volumetypes.List(client.ServiceClient(fakeServer), volumetypes.ListOpts{ - Name: "test-type", - Description: "test", - IsPublic: volumetypes.VisibilityPublic, - ExtraSpecs: map[string]string{"storage_protocol": "nfs"}, - }).EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) { - return true, nil - }) + actual, err := volumetypes.ExtractVolumeTypes(allPages) th.AssertNoErr(t, err) + th.AssertEquals(t, 1, len(actual)) + th.AssertEquals(t, "test-type", actual[0].Name) + th.AssertEquals(t, "996af3df-92fd-4814-a0ee-ba5f899aa1ec", actual[0].ID) + th.AssertEquals(t, "test", actual[0].Description) + th.AssertEquals(t, true, actual[0].IsPublic) + th.AssertEquals(t, true, actual[0].PublicAccess) + th.AssertEquals(t, "nfs", actual[0].ExtraSpecs["storage_protocol"]) } func TestListDescriptionParam(t *testing.T) { fakeServer := th.SetupHTTP() defer fakeServer.Teardown() result := make(map[string]string) - HandleListIsPublicParam(t, fakeServer, result) + HandleListWithDescriptionFilter(t, fakeServer, result) - // Test with description filter result["is_public"] = "None" result["description"] = "test" - err := volumetypes.List(client.ServiceClient(fakeServer), volumetypes.ListOpts{ + allPages, err := volumetypes.List(client.ServiceClient(fakeServer), volumetypes.ListOpts{ Description: "test", - }).EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) { - return true, nil - }) + }).AllPages(context.TODO()) th.AssertNoErr(t, err) - - // Test with description, is_public, and extra_specs together - result["is_public"] = "true" - result["description"] = "test" - result["extra_specs"] = "{'multiattach':' True'}" - err = volumetypes.List(client.ServiceClient(fakeServer), volumetypes.ListOpts{ - Description: "test", - IsPublic: volumetypes.VisibilityPublic, - ExtraSpecs: map[string]string{"multiattach": " True"}, - }).EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) { - return true, nil - }) + actual, err := volumetypes.ExtractVolumeTypes(allPages) th.AssertNoErr(t, err) + th.AssertEquals(t, 1, len(actual)) + th.AssertEquals(t, "test", actual[0].Description) + th.AssertEquals(t, "test-type", actual[0].Name) + th.AssertEquals(t, "ab948f0a-13ed-47c8-b9be-cade0beb0706", actual[0].ID) + th.AssertEquals(t, true, actual[0].IsPublic) + th.AssertEquals(t, true, actual[0].PublicAccess) + th.AssertEquals(t, " True", actual[0].ExtraSpecs["multiattach"]) } func TestListExtraSpecsParam(t *testing.T) { fakeServer := th.SetupHTTP() defer fakeServer.Teardown() result := make(map[string]string) - HandleListIsPublicParam(t, fakeServer, result) - - // Test with extra_specs filter result["is_public"] = "None" result["extra_specs"] = "{'storage_protocol':'nfs'}" - err := volumetypes.List(client.ServiceClient(fakeServer), volumetypes.ListOpts{ + HandleListWithExtraSpecsFilter(t, fakeServer, result) + + // Test with extra_specs filter + allPages, err := volumetypes.List(client.ServiceClient(fakeServer), volumetypes.ListOpts{ ExtraSpecs: map[string]string{"storage_protocol": "nfs"}, - }).EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) { - return true, nil - }) + }).AllPages(context.TODO()) + th.AssertNoErr(t, err) + actual, err := volumetypes.ExtractVolumeTypes(allPages) th.AssertNoErr(t, err) + th.AssertEquals(t, 1, len(actual)) + th.AssertEquals(t, "nfs-type", actual[0].Name) + th.AssertEquals(t, "6b0cfee7-48b6-41b7-9d68-0d74cbdc08de", actual[0].ID) + th.AssertEquals(t, "NFS storage type", actual[0].Description) + th.AssertEquals(t, true, actual[0].IsPublic) + th.AssertEquals(t, true, actual[0].PublicAccess) + th.AssertEquals(t, "nfs", actual[0].ExtraSpecs["storage_protocol"]) // Test with multiple extra_specs result["extra_specs"] = "{'multiattach':' True', 'replication_enabled':' True', 'RESKEY:availability_zones':'zone'}" - err = volumetypes.List(client.ServiceClient(fakeServer), volumetypes.ListOpts{ + allPages, err = volumetypes.List(client.ServiceClient(fakeServer), volumetypes.ListOpts{ ExtraSpecs: map[string]string{ "multiattach": " True", "replication_enabled": " True", "RESKEY:availability_zones": "zone", }, - }).EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) { - return true, nil - }) + }).AllPages(context.TODO()) + th.AssertNoErr(t, err) + actual, err = volumetypes.ExtractVolumeTypes(allPages) th.AssertNoErr(t, err) + th.AssertEquals(t, 1, len(actual)) + th.AssertEquals(t, "multiattach-type", actual[0].Name) + th.AssertEquals(t, "e1fc0553-0357-4206-af30-23137ee5f743", actual[0].ID) + th.AssertEquals(t, "Multiattach volume type", actual[0].Description) + th.AssertEquals(t, true, actual[0].IsPublic) + th.AssertEquals(t, true, actual[0].PublicAccess) + th.AssertEquals(t, " True", actual[0].ExtraSpecs["multiattach"]) + th.AssertEquals(t, " True", actual[0].ExtraSpecs["replication_enabled"]) + th.AssertEquals(t, "zone", actual[0].ExtraSpecs["RESKEY:availability_zones"]) } func TestVolumeTypeExtraSpecsList(t *testing.T) { From 0460120be71c49dcfa1c5910217c5906805cbd50 Mon Sep 17 00:00:00 2001 From: Konstantin Eremin Date: Thu, 18 Dec 2025 02:23:03 +0300 Subject: [PATCH 291/429] Add Volume Typres acceptance test, fix unit test --- .../openstack/blockstorage/v3/blockstorage.go | 2 +- .../blockstorage/v3/volumetypes_test.go | 100 +++++++++++++++++- .../v3/volumetypes/testing/fixtures_test.go | 33 ++---- .../v3/volumetypes/testing/requests_test.go | 22 ---- 4 files changed, 106 insertions(+), 51 deletions(-) diff --git a/internal/acceptance/openstack/blockstorage/v3/blockstorage.go b/internal/acceptance/openstack/blockstorage/v3/blockstorage.go index 16e0a23dd1..782089963d 100644 --- a/internal/acceptance/openstack/blockstorage/v3/blockstorage.go +++ b/internal/acceptance/openstack/blockstorage/v3/blockstorage.go @@ -158,7 +158,7 @@ func CreateVolumeType(t *testing.T, client *gophercloud.ServiceClient) (*volumet createOpts := volumetypes.CreateOpts{ Name: name, - ExtraSpecs: map[string]string{"volume_backend_name": "fake_backend_name"}, + ExtraSpecs: map[string]string{"volume_backend_name": "fake_backend_name", "RESKEY:availability_zones": "zone", "multiattach": " True"}, Description: description, } diff --git a/internal/acceptance/openstack/blockstorage/v3/volumetypes_test.go b/internal/acceptance/openstack/blockstorage/v3/volumetypes_test.go index f19fd033de..4b2a1bdfaa 100644 --- a/internal/acceptance/openstack/blockstorage/v3/volumetypes_test.go +++ b/internal/acceptance/openstack/blockstorage/v3/volumetypes_test.go @@ -4,6 +4,7 @@ package v3 import ( "context" + "fmt" "testing" "github.com/gophercloud/gophercloud/v2/internal/acceptance/clients" @@ -13,7 +14,7 @@ import ( th "github.com/gophercloud/gophercloud/v2/testhelper" ) -func TestVolumeTypes(t *testing.T) { +func TestVolumeTypesCRUD(t *testing.T) { clients.RequireAdmin(t) client, err := clients.NewBlockStorageV3Client() @@ -39,9 +40,9 @@ func TestVolumeTypes(t *testing.T) { th.AssertEquals(t, found, true) + name := vt.Name + "-updated" + description := vt.Description + "-updated" isPublic := false - name := vt.Name + "-UPDATED" - description := "" updateOpts := volumetypes.UpdateOpts{ Name: &name, Description: &description, @@ -55,6 +56,99 @@ func TestVolumeTypes(t *testing.T) { th.AssertEquals(t, name, newVT.Name) th.AssertEquals(t, description, newVT.Description) th.AssertEquals(t, isPublic, newVT.IsPublic) + + for _, tt := range []struct { + name string + opts volumetypes.ListOpts + expectedVolumeTypes int + }{ + { + name: "Volume Type Name", + opts: volumetypes.ListOpts{ + Name: newVT.Name, + }, + expectedVolumeTypes: 1, + }, + { + name: "Description", + opts: volumetypes.ListOpts{ + Description: "create_from_gophercloud-updated", + }, + expectedVolumeTypes: 1, + }, + { + name: "Partitial Extra Specs", + opts: volumetypes.ListOpts{ + ExtraSpecs: map[string]string{ + "volume_backend_name": "fake_backend_name", + "RESKEY:availability_zones": "zone", + }, + }, + expectedVolumeTypes: 1, + }, + { + name: "Full Extra Specs", + opts: volumetypes.ListOpts{ + ExtraSpecs: map[string]string{ + "volume_backend_name": "fake_backend_name", + "RESKEY:availability_zones": "zone", + "multiattach": " True", + }, + }, + expectedVolumeTypes: 1, + }, + { + name: "Extra Specs Not Found", + opts: volumetypes.ListOpts{ + ExtraSpecs: map[string]string{ + "volume_backend_name": "fake_backend_name", + "RESKEY:availability_zones": "zone", + "multiattach": " True", + "another_one_spec": "another_one_value", + }, + }, + expectedVolumeTypes: 0, + }, + } { + t.Run(fmt.Sprintf("List volumetypes by %s", tt.name), func(t *testing.T) { + allPages, err := volumetypes.List(client, tt.opts).AllPages(context.TODO()) + th.AssertNoErr(t, err) + + allVolumeTypes, err := volumetypes.ExtractVolumeTypes(allPages) + th.AssertNoErr(t, err) + + logVolumeTypes := func() { + for _, volumetype := range allVolumeTypes { + tools.PrintResource(t, volumetype) + } + } + + if tt.name != "Extra Specs Not Found" { + if len(allVolumeTypes) != tt.expectedVolumeTypes { + if len(allVolumeTypes) == 0 { + t.Fatalf("Volume type not found") + } + } + } else { + if len(allVolumeTypes) != 0 { + logVolumeTypes() + t.Fatalf("Expected %d volume type but got %d", tt.expectedVolumeTypes, len(allVolumeTypes)) + } + } + func() { + for _, volumetype := range allVolumeTypes { + if tt.name != "Extra Specs Not Found" { + if volumetype.ID == newVT.ID { + return + } else { + logVolumeTypes() + t.Fatalf("Returned volume types did not contain expected volume type") + } + } + } + }() + }) + } } func TestVolumeTypesExtraSpecs(t *testing.T) { diff --git a/openstack/blockstorage/v3/volumetypes/testing/fixtures_test.go b/openstack/blockstorage/v3/volumetypes/testing/fixtures_test.go index af09e18086..d305f22fbb 100644 --- a/openstack/blockstorage/v3/volumetypes/testing/fixtures_test.go +++ b/openstack/blockstorage/v3/volumetypes/testing/fixtures_test.go @@ -278,9 +278,13 @@ func HandleListWithExtraSpecsFilter(t *testing.T, fakeServer th.FakeServer, valu extraSpecsFilter := r.Form.Get("extra_specs") - // Determine which volume type to return based on extra_specs filter - switch extraSpecsFilter { - case "{'storage_protocol':'nfs'}": + // Determine which volume type to return based on extra_specs filter. + // Note: We only test with a single extra_spec value because testing multiple + // values is not feasible due to the non-deterministic order of map keys in Go. + // The order of keys in the serialized string can vary between runs, making + // it impossible to reliably match the expected string without adding complex + // normalization code that would clutter the test. + if extraSpecsFilter == "{'storage_protocol':'nfs'}" { // Return only nfs-type fmt.Fprint(w, ` { @@ -299,28 +303,7 @@ func HandleListWithExtraSpecsFilter(t *testing.T, fakeServer th.FakeServer, valu ] } `) - case "{'multiattach':' True', 'replication_enabled':' True', 'RESKEY:availability_zones':'zone'}": - // Return only multiattach-type - fmt.Fprint(w, ` -{ - "volume_types": [ - { - "name": "multiattach-type", - "qos_specs_id": null, - "os-volume-type-access:is_public": true, - "extra_specs": { - "multiattach": " True", - "replication_enabled": " True", - "RESKEY:availability_zones": "zone" - }, - "is_public": true, - "id": "e1fc0553-0357-4206-af30-23137ee5f743", - "description": "Multiattach volume type" - } - ] -} -`) - default: + } else { // Default: return empty list fmt.Fprint(w, `{"volume_types": []}`) } diff --git a/openstack/blockstorage/v3/volumetypes/testing/requests_test.go b/openstack/blockstorage/v3/volumetypes/testing/requests_test.go index 83b9ecd7fb..da830502ee 100644 --- a/openstack/blockstorage/v3/volumetypes/testing/requests_test.go +++ b/openstack/blockstorage/v3/volumetypes/testing/requests_test.go @@ -230,28 +230,6 @@ func TestListExtraSpecsParam(t *testing.T) { th.AssertEquals(t, true, actual[0].IsPublic) th.AssertEquals(t, true, actual[0].PublicAccess) th.AssertEquals(t, "nfs", actual[0].ExtraSpecs["storage_protocol"]) - - // Test with multiple extra_specs - result["extra_specs"] = "{'multiattach':' True', 'replication_enabled':' True', 'RESKEY:availability_zones':'zone'}" - allPages, err = volumetypes.List(client.ServiceClient(fakeServer), volumetypes.ListOpts{ - ExtraSpecs: map[string]string{ - "multiattach": " True", - "replication_enabled": " True", - "RESKEY:availability_zones": "zone", - }, - }).AllPages(context.TODO()) - th.AssertNoErr(t, err) - actual, err = volumetypes.ExtractVolumeTypes(allPages) - th.AssertNoErr(t, err) - th.AssertEquals(t, 1, len(actual)) - th.AssertEquals(t, "multiattach-type", actual[0].Name) - th.AssertEquals(t, "e1fc0553-0357-4206-af30-23137ee5f743", actual[0].ID) - th.AssertEquals(t, "Multiattach volume type", actual[0].Description) - th.AssertEquals(t, true, actual[0].IsPublic) - th.AssertEquals(t, true, actual[0].PublicAccess) - th.AssertEquals(t, " True", actual[0].ExtraSpecs["multiattach"]) - th.AssertEquals(t, " True", actual[0].ExtraSpecs["replication_enabled"]) - th.AssertEquals(t, "zone", actual[0].ExtraSpecs["RESKEY:availability_zones"]) } func TestVolumeTypeExtraSpecsList(t *testing.T) { From c830e599366eb4b274cd3b5783b9683293171b1c Mon Sep 17 00:00:00 2001 From: Chi Wai Chan Date: Thu, 18 Dec 2025 14:43:13 +0800 Subject: [PATCH 292/429] fix (image/v2/images): image v2 unmarshal issue --- openstack/image/v2/images/results.go | 10 ++++- .../image/v2/images/testing/fixtures_test.go | 43 ++++++++++++++++++- .../image/v2/images/testing/requests_test.go | 7 +-- 3 files changed, 54 insertions(+), 6 deletions(-) diff --git a/openstack/image/v2/images/results.go b/openstack/image/v2/images/results.go index f21101cc87..566bbb4e82 100644 --- a/openstack/image/v2/images/results.go +++ b/openstack/image/v2/images/results.go @@ -70,7 +70,7 @@ type Image struct { // Properties is a set of key-value pairs, if any, that are associated with // the image. - Properties map[string]any + Properties map[string]any `json:"-"` // CreatedAt is the date when the image has been created. CreatedAt time.Time `json:"created_at"` @@ -102,6 +102,7 @@ func (r *Image) UnmarshalJSON(b []byte) error { type tmp Image var s struct { tmp + Properties string `json:"properties"` SizeBytes any `json:"size"` OpenStackImageImportMethods string `json:"openstack-image-import-methods"` OpenStackImageStoreIDs string `json:"openstack-image-store-ids"` @@ -123,7 +124,7 @@ func (r *Image) UnmarshalJSON(b []byte) error { return fmt.Errorf("unknown type for SizeBytes: %v (value: %v)", reflect.TypeOf(t), t) } - // Bundle all other fields into Properties + // Bundle all other fields into Properties, except for the field named "properties" var result any err = json.Unmarshal(b, &result) if err != nil { @@ -137,6 +138,11 @@ func (r *Image) UnmarshalJSON(b []byte) error { r.Properties = gophercloud.RemainingKeys(Image{}, resultMap) } + // Add the "properties" field to the image since it's not included in above step (i.e. in remaining keys) + if s.Properties != "" { + r.Properties["properties"] = s.Properties + } + if v := strings.FieldsFunc(strings.TrimSpace(s.OpenStackImageImportMethods), splitFunc); len(v) > 0 { r.OpenStackImageImportMethods = v } diff --git a/openstack/image/v2/images/testing/fixtures_test.go b/openstack/image/v2/images/testing/fixtures_test.go index 0ec25214d1..9665e4ed55 100644 --- a/openstack/image/v2/images/testing/fixtures_test.go +++ b/openstack/image/v2/images/testing/fixtures_test.go @@ -19,7 +19,7 @@ type imageEntry struct { // HandleImageListSuccessfully test setup func HandleImageListSuccessfully(t *testing.T, fakeServer th.FakeServer) { - images := make([]imageEntry, 3) + images := make([]imageEntry, 4) images[0] = imageEntry{"cirros-0.3.4-x86_64-uec", `{ @@ -98,6 +98,46 @@ func HandleImageListSuccessfully(t *testing.T, fakeServer th.FakeServer) { "hw_disk_bus_model": "virtio-scsi", "hw_scsi_model": "virtio-scsi" }`} + images[3] = imageEntry{"ubuntu-24.04-server-cloudimg-amd64.img", + `{ + "owner_specified.openstack.md5": "", + "owner_specified.openstack.object": "images/johndoe-noble-iso-test", + "owner_specified.openstack.sha256": "", + "properties": "{'hypervisor_type': 'qemu', 'architecture': 'x86_64'}", + "additional_property": "{\"name\": \"noble\", \"size\": 100, \"hidden\": false}", + "name": "johndoe-noble-iso-test", + "disk_format": "iso", + "container_format": "bare", + "visibility": "shared", + "size": 3303444480, + "virtual_size": null, + "status": "active", + "checksum": "19fe5793f7411cfe124d9fa0c0f4d449", + "protected": false, + "min_ram": 0, + "min_disk": 0, + "owner": "dfdfed1a51504178abe8c5eeaeb8343b", + "os_hidden": false, + "os_hash_algo": "sha256", + "os_hash_value": "c3514bf0056180d09376462a7a1b4f213c1d6e8ea67fae5c25099c6fd3d8274b", + "id": "370ba8b7-3e72-4f9d-8623-7d9c95e4c28d", + "created_at": "2025-12-18T02:05:15Z", + "updated_at": "2025-12-18T02:42:05Z", + "locations": [ + { + "url": "rbd://eea9d068-c18c-11ed-8dc0-013aacb71b80/glance/370ba8b7-3e72-4f9d-8623-7d9c95e4c28d/snap", + "metadata": { + "store": "ceph" + } + } + ], + "direct_url": "rbd://eea9d068-c18c-11ed-8dc0-013aacb71b80/glance/370ba8b7-3e72-4f9d-8623-7d9c95e4c28d/snap", + "tags": [], + "self": "/v2/images/370ba8b7-3e72-4f9d-8623-7d9c95e4c28d", + "file": "/v2/images/370ba8b7-3e72-4f9d-8623-7d9c95e4c28d/file", + "schema": "/v2/schemas/image", + "stores": "ceph" + }`} fakeServer.Mux.HandleFunc("/images", func(w http.ResponseWriter, r *http.Request) { th.TestMethod(t, r, "GET") @@ -282,6 +322,7 @@ func HandleImageGetSuccessfully(t *testing.T, fakeServer th.FakeServer) { "hw_disk_bus": "scsi", "hw_disk_bus_model": "virtio-scsi", "hw_scsi_model": "virtio-scsi" + "properties": "{\"test\": true}", }`) }) } diff --git a/openstack/image/v2/images/testing/requests_test.go b/openstack/image/v2/images/testing/requests_test.go index 90c9833be1..d98ac88ae0 100644 --- a/openstack/image/v2/images/testing/requests_test.go +++ b/openstack/image/v2/images/testing/requests_test.go @@ -40,8 +40,8 @@ func TestListImage(t *testing.T) { th.AssertNoErr(t, err) t.Logf("--------\n%d images listed on %d pages.\n", count, pages) - th.AssertEquals(t, 3, pages) - th.AssertEquals(t, 3, count) + th.AssertEquals(t, 4, pages) + th.AssertEquals(t, 4, count) } func TestAllPagesImage(t *testing.T) { @@ -54,7 +54,7 @@ func TestAllPagesImage(t *testing.T) { th.AssertNoErr(t, err) images, err := images.ExtractImages(pages) th.AssertNoErr(t, err) - th.AssertEquals(t, 3, len(images)) + th.AssertEquals(t, 4, len(images)) } func TestCreateImage(t *testing.T) { @@ -239,6 +239,7 @@ func TestGetImage(t *testing.T) { "hw_disk_bus": "scsi", "hw_disk_bus_model": "virtio-scsi", "hw_scsi_model": "virtio-scsi", + "properties": "{\"test\": true}", }, } From 83f935cd792742223852ec52b3002e586689a7f7 Mon Sep 17 00:00:00 2001 From: Chi Wai Chan Date: Fri, 19 Dec 2025 12:46:29 +0800 Subject: [PATCH 293/429] test (image/v2): improve CreateEmptyImage --- internal/acceptance/openstack/image/v2/imageservice.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/acceptance/openstack/image/v2/imageservice.go b/internal/acceptance/openstack/image/v2/imageservice.go index caa832ce6b..0454a74b88 100644 --- a/internal/acceptance/openstack/image/v2/imageservice.go +++ b/internal/acceptance/openstack/image/v2/imageservice.go @@ -38,6 +38,7 @@ func CreateEmptyImage(t *testing.T, client *gophercloud.ServiceClient) (*images. Visibility: &visibility, Properties: map[string]string{ "architecture": "x86_64", + "properties": "{'hypervisor_type': 'qemu', 'architecture': 'x86_64'}", }, Tags: []string{"foo", "bar", "baz"}, } @@ -56,6 +57,7 @@ func CreateEmptyImage(t *testing.T, client *gophercloud.ServiceClient) (*images. th.CheckEquals(t, newImage.Name, name) th.CheckEquals(t, newImage.Properties["architecture"], "x86_64") + th.CheckEquals(t, newImage.Properties["properties"], "{'hypervisor_type': 'qemu', 'architecture': 'x86_64'}") return newImage, nil } From 77360388fc7e0736e5c4d56e002e607131cdde57 Mon Sep 17 00:00:00 2001 From: Chi Wai Chan Date: Fri, 19 Dec 2025 18:13:26 +0800 Subject: [PATCH 294/429] test: add missing comma --- openstack/image/v2/images/testing/fixtures_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openstack/image/v2/images/testing/fixtures_test.go b/openstack/image/v2/images/testing/fixtures_test.go index 9665e4ed55..0f47975677 100644 --- a/openstack/image/v2/images/testing/fixtures_test.go +++ b/openstack/image/v2/images/testing/fixtures_test.go @@ -321,8 +321,8 @@ func HandleImageGetSuccessfully(t *testing.T, fakeServer th.FakeServer) { "virtual_size": null, "hw_disk_bus": "scsi", "hw_disk_bus_model": "virtio-scsi", - "hw_scsi_model": "virtio-scsi" - "properties": "{\"test\": true}", + "hw_scsi_model": "virtio-scsi", + "properties": "{\"test\": true}" }`) }) } From 7e2131ea0837c5d1d0b178f394afd17f7639fe26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Mon, 22 Dec 2025 09:43:02 +0100 Subject: [PATCH 295/429] GHA: do not add backport-v2 labels to v2 PRs As seen in [1], we shouldn't add the `backport-v2` label to PRs that are already submitted against `v2` branch. [1] https://github.com/gophercloud/gophercloud/pull/3590#issuecomment-3681014409 --- .github/workflows/label-pr.yaml | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/.github/workflows/label-pr.yaml b/.github/workflows/label-pr.yaml index 8c7e9c55fa..fb3cf97505 100644 --- a/.github/workflows/label-pr.yaml +++ b/.github/workflows/label-pr.yaml @@ -43,19 +43,44 @@ jobs: - name: Add label semver:patch if: steps.go-apidiff.outputs.semver-type == 'patch' - run: gh pr edit "$NUMBER" --add-label "semver:patch,backport-v2" --remove-label "semver:major,semver:minor" + run: | + LABELS="semver:patch" + REMOVE_LABELS="semver:major,semver:minor" + + # Only add backport-v2 if not already targeting v2 or lower + if [[ "$BASE_REF" != "v2" && "$BASE_REF" != "v1" ]]; then + LABELS="$LABELS,backport-v2" + else + REMOVE_LABELS="$REMOVE_LABELS,backport-v2" + fi + + gh pr edit "$NUMBER" --add-label "$LABELS" --remove-label "$REMOVE_LABELS" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} NUMBER: ${{ github.event.pull_request.number }} + BASE_REF: ${{ github.base_ref }} - name: Add label semver:minor if: steps.go-apidiff.outputs.semver-type == 'minor' - run: gh pr edit "$NUMBER" --add-label "semver:minor,backport-v2" --remove-label "semver:major,semver:patch,backport-v1" + run: | + LABELS="semver:minor" + REMOVE_LABELS="semver:major,semver:patch" + + # Only add backport-v2 if not already targeting v2 or lower + if [[ "$BASE_REF" != "v2" && "$BASE_REF" != "v1" ]]; then + LABELS="$LABELS,backport-v2" + REMOVE_LABELS="$REMOVE_LABELS,backport-v1" + else + REMOVE_LABELS="$REMOVE_LABELS,backport-v2,backport-v1" + fi + + gh pr edit "$NUMBER" --add-label "$LABELS" --remove-label "$REMOVE_LABELS" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} NUMBER: ${{ github.event.pull_request.number }} + BASE_REF: ${{ github.base_ref }} - name: Add label semver:major if: steps.go-apidiff.outputs.semver-type == 'major' From 12d6828ae59a8a535ee813e3e4e448748bb56f40 Mon Sep 17 00:00:00 2001 From: Konstantin Eremin Date: Mon, 22 Dec 2025 21:29:38 +0300 Subject: [PATCH 296/429] Remove extra_specs, fix tests --- .../blockstorage/v3/volumetypes_test.go | 52 ++++--------------- .../blockstorage/v3/volumetypes/requests.go | 4 -- .../v3/volumetypes/testing/requests_test.go | 24 --------- 3 files changed, 11 insertions(+), 69 deletions(-) diff --git a/internal/acceptance/openstack/blockstorage/v3/volumetypes_test.go b/internal/acceptance/openstack/blockstorage/v3/volumetypes_test.go index 4b2a1bdfaa..7fa8457b19 100644 --- a/internal/acceptance/openstack/blockstorage/v3/volumetypes_test.go +++ b/internal/acceptance/openstack/blockstorage/v3/volumetypes_test.go @@ -56,6 +56,7 @@ func TestVolumeTypesCRUD(t *testing.T) { th.AssertEquals(t, name, newVT.Name) th.AssertEquals(t, description, newVT.Description) th.AssertEquals(t, isPublic, newVT.IsPublic) + newVisibility := volumetypes.VisibilityPrivate for _, tt := range []struct { name string @@ -77,38 +78,12 @@ func TestVolumeTypesCRUD(t *testing.T) { expectedVolumeTypes: 1, }, { - name: "Partitial Extra Specs", + name: "Is Public", opts: volumetypes.ListOpts{ - ExtraSpecs: map[string]string{ - "volume_backend_name": "fake_backend_name", - "RESKEY:availability_zones": "zone", - }, + IsPublic: newVisibility, }, expectedVolumeTypes: 1, }, - { - name: "Full Extra Specs", - opts: volumetypes.ListOpts{ - ExtraSpecs: map[string]string{ - "volume_backend_name": "fake_backend_name", - "RESKEY:availability_zones": "zone", - "multiattach": " True", - }, - }, - expectedVolumeTypes: 1, - }, - { - name: "Extra Specs Not Found", - opts: volumetypes.ListOpts{ - ExtraSpecs: map[string]string{ - "volume_backend_name": "fake_backend_name", - "RESKEY:availability_zones": "zone", - "multiattach": " True", - "another_one_spec": "another_one_value", - }, - }, - expectedVolumeTypes: 0, - }, } { t.Run(fmt.Sprintf("List volumetypes by %s", tt.name), func(t *testing.T) { allPages, err := volumetypes.List(client, tt.opts).AllPages(context.TODO()) @@ -123,29 +98,24 @@ func TestVolumeTypesCRUD(t *testing.T) { } } - if tt.name != "Extra Specs Not Found" { - if len(allVolumeTypes) != tt.expectedVolumeTypes { - if len(allVolumeTypes) == 0 { - t.Fatalf("Volume type not found") - } + if len(allVolumeTypes) != tt.expectedVolumeTypes { + if len(allVolumeTypes) == 0 { + t.Fatalf("Volume type not found") } } else { - if len(allVolumeTypes) != 0 { + if len(allVolumeTypes) > 1 { logVolumeTypes() t.Fatalf("Expected %d volume type but got %d", tt.expectedVolumeTypes, len(allVolumeTypes)) } } func() { for _, volumetype := range allVolumeTypes { - if tt.name != "Extra Specs Not Found" { - if volumetype.ID == newVT.ID { - return - } else { - logVolumeTypes() - t.Fatalf("Returned volume types did not contain expected volume type") - } + if volumetype.ID == newVT.ID { + return } } + logVolumeTypes() + t.Fatalf("Returned volume types did not contain expected volume type") }() }) } diff --git a/openstack/blockstorage/v3/volumetypes/requests.go b/openstack/blockstorage/v3/volumetypes/requests.go index ca8c8be754..d62db1c8b6 100644 --- a/openstack/blockstorage/v3/volumetypes/requests.go +++ b/openstack/blockstorage/v3/volumetypes/requests.go @@ -80,10 +80,6 @@ type ListOpts struct { // Specifies whether the query should include public or private Volume Types. // By default, it queries both types. IsPublic visibility `q:"is_public"` - // ExtraSpecs will filter results based on specified extra specs. - // The map key is the extra spec name, and the value is the filter value. - // For example: map[string]string{"multiattach": " True", "storage_protocol": "nfs"} - ExtraSpecs map[string]string `q:"extra_specs"` // Comma-separated list of sort keys and optional sort directions in the // form of [:]. Sort string `q:"sort"` diff --git a/openstack/blockstorage/v3/volumetypes/testing/requests_test.go b/openstack/blockstorage/v3/volumetypes/testing/requests_test.go index da830502ee..b64a269c59 100644 --- a/openstack/blockstorage/v3/volumetypes/testing/requests_test.go +++ b/openstack/blockstorage/v3/volumetypes/testing/requests_test.go @@ -208,30 +208,6 @@ func TestListDescriptionParam(t *testing.T) { th.AssertEquals(t, " True", actual[0].ExtraSpecs["multiattach"]) } -func TestListExtraSpecsParam(t *testing.T) { - fakeServer := th.SetupHTTP() - defer fakeServer.Teardown() - result := make(map[string]string) - result["is_public"] = "None" - result["extra_specs"] = "{'storage_protocol':'nfs'}" - HandleListWithExtraSpecsFilter(t, fakeServer, result) - - // Test with extra_specs filter - allPages, err := volumetypes.List(client.ServiceClient(fakeServer), volumetypes.ListOpts{ - ExtraSpecs: map[string]string{"storage_protocol": "nfs"}, - }).AllPages(context.TODO()) - th.AssertNoErr(t, err) - actual, err := volumetypes.ExtractVolumeTypes(allPages) - th.AssertNoErr(t, err) - th.AssertEquals(t, 1, len(actual)) - th.AssertEquals(t, "nfs-type", actual[0].Name) - th.AssertEquals(t, "6b0cfee7-48b6-41b7-9d68-0d74cbdc08de", actual[0].ID) - th.AssertEquals(t, "NFS storage type", actual[0].Description) - th.AssertEquals(t, true, actual[0].IsPublic) - th.AssertEquals(t, true, actual[0].PublicAccess) - th.AssertEquals(t, "nfs", actual[0].ExtraSpecs["storage_protocol"]) -} - func TestVolumeTypeExtraSpecsList(t *testing.T) { fakeServer := th.SetupHTTP() defer fakeServer.Teardown() From 53e1258a8d7447fbd5ab913ca0a9545af09113b5 Mon Sep 17 00:00:00 2001 From: Konstantin Eremin Date: Wed, 24 Dec 2025 01:31:26 +0300 Subject: [PATCH 297/429] LoadBalancer V2: Add availability zone profiles Add availability zone requests Add tests Add docs --- .../v2/availabilityzoneprofiles_test.go | 54 ++++++ .../v2/availabilityzoneprofiles/doc.go | 57 +++++++ .../v2/availabilityzoneprofiles/requests.go | 145 ++++++++++++++++ .../v2/availabilityzoneprofiles/results.go | 96 +++++++++++ .../availabilityzoneprofiles/testing/doc.go | 1 + .../testing/fixtures.go | 159 ++++++++++++++++++ .../testing/requests_test.go | 122 ++++++++++++++ .../v2/availabilityzoneprofiles/urls.go | 16 ++ 8 files changed, 650 insertions(+) create mode 100644 internal/acceptance/openstack/loadbalancer/v2/availabilityzoneprofiles_test.go create mode 100644 openstack/loadbalancer/v2/availabilityzoneprofiles/doc.go create mode 100644 openstack/loadbalancer/v2/availabilityzoneprofiles/requests.go create mode 100644 openstack/loadbalancer/v2/availabilityzoneprofiles/results.go create mode 100644 openstack/loadbalancer/v2/availabilityzoneprofiles/testing/doc.go create mode 100644 openstack/loadbalancer/v2/availabilityzoneprofiles/testing/fixtures.go create mode 100644 openstack/loadbalancer/v2/availabilityzoneprofiles/testing/requests_test.go create mode 100644 openstack/loadbalancer/v2/availabilityzoneprofiles/urls.go diff --git a/internal/acceptance/openstack/loadbalancer/v2/availabilityzoneprofiles_test.go b/internal/acceptance/openstack/loadbalancer/v2/availabilityzoneprofiles_test.go new file mode 100644 index 0000000000..fc991caa2c --- /dev/null +++ b/internal/acceptance/openstack/loadbalancer/v2/availabilityzoneprofiles_test.go @@ -0,0 +1,54 @@ +//go:build acceptance || networking || loadbalancer || flavorprofiles + +package v2 + +import ( + "context" + "testing" + + "github.com/gophercloud/gophercloud/v2/internal/acceptance/clients" + "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" + "github.com/gophercloud/gophercloud/v2/internal/ptr" + "github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/availabilityzoneprofiles" + + th "github.com/gophercloud/gophercloud/v2/testhelper" +) + +func TestAvailabilityZoneProfilesList(t *testing.T) { + client, err := clients.NewLoadBalancerV2Client() + th.AssertNoErr(t, err) + + allPages, err := availabilityzoneprofiles.List(client, nil).AllPages(context.TODO()) + th.AssertNoErr(t, err) + + allAvailabilityZoneProfiles, err := availabilityzoneprofiles.ExtractFlavorProfiles(allPages) + th.AssertNoErr(t, err) + + for _, availabilityzoneprofile := range allAvailabilityZoneProfiles { + tools.PrintResource(t, availabilityzoneprofile) + } +} + +func TestAvailabilityZoneProfilesCRUD(t *testing.T) { + lbClient, err := clients.NewLoadBalancerV2Client() + th.AssertNoErr(t, err) + + availabilityZoneProfile, err := CreateAvailabilityZonerProfile(t, lbClient) + th.AssertNoErr(t, err) + defer DeleteAvailabilityZoneProfile(t, lbClient, availabilityZoneProfile) + + tools.PrintResource(t, availabilityZoneProfile) + + th.AssertEquals(t, "amphora", availabilityZoneProfile.ProviderName) + + availabilityZoneProfileUpdateOpts := availabilityzoneprofiles.UpdateOpts{ + Name: ptr.To(tools.RandomString("TESTACCTUP-", 8)), + } + + availabilityZoneProfileUpdated, err := availabilityzoneprofiles.Update(context.TODO(), lbClient, availabilityZoneProfile.ID, availabilityZoneProfileUpdateOpts).Extract() + th.AssertNoErr(t, err) + + th.AssertEquals(t, *availabilityZoneProfileUpdateOpts.Name, availabilityZoneProfileUpdated.Name) + + t.Logf("Successfully updated availabiltyzoneprofile %s", availabilityZoneProfileUpdated.Name) +} diff --git a/openstack/loadbalancer/v2/availabilityzoneprofiles/doc.go b/openstack/loadbalancer/v2/availabilityzoneprofiles/doc.go new file mode 100644 index 0000000000..a6a47f205f --- /dev/null +++ b/openstack/loadbalancer/v2/availabilityzoneprofiles/doc.go @@ -0,0 +1,57 @@ +/* +Package availabilityzoneprofiles provides information and interaction +with AvailabilityZoneProfiles for the OpenStack Load-balancing service. + +Example to List AvailabilityZoneProfiles + + listOpts := availabilityzoneprofiles.ListOpts{} + + allPages, err := availabilityzoneprofiles.List(octaviaClient, listOpts).AllPages(context.TODO()) + if err != nil { + panic(err) + } + + allAvailabilityZoneProfiles, err := availabilityzoneprofiles.ExtractAvailabilityZoneProfiles(allPages) + if err != nil { + panic(err) + } + + for _, availabilityZoneProfile := range allAvailabilityZoneProfiles { + fmt.Printf("%+v\n", availabilityZoneProfile) + } + +Example to Create a AvailabilityZoneProfile + + createOpts := availabilityzoneprofiles.CreateOpts{ + Name: "availability-zone-profile", + ProviderName: "amphora", + AvailabilityZoneData: "{\"compute_zone\": \"nova\", \"volume_zone\": \"nova\"}", + } + + availabilityZoneProfile, err := availabilityzoneprofiles.Create(context.TODO(), octaviaClient, createOpts).Extract() + if err != nil { + panic(err) + } + +Example to Update a AvailabilityZoneProfile + + availabilityZoneProfileID := "0c359d38-6164-498f-8409-5b11d05b6226" + + updateOpts := availabilityzoneprofiles.UpdateOpts{ + Name: "availability-zone-profile-updated", + } + + availabilityZoneProfile, err := availabilityzoneprofiles.Update(context.TODO(), octaviaClient, availabilityZoneProfileID, updateOpts).Extract() + if err != nil { + panic(err) + } + +Example to Delete a AvailabilityZoneProfile + + availabilityZoneProfileID := "0c359d38-6164-498f-8409-5b11d05b6226" + err := availabilityzoneprofiles.Delete(context.TODO(), octaviaClient, availabilityZoneProfileID).ExtractErr() + if err != nil { + panic(err) + } +*/ +package availabilityzoneprofiles diff --git a/openstack/loadbalancer/v2/availabilityzoneprofiles/requests.go b/openstack/loadbalancer/v2/availabilityzoneprofiles/requests.go new file mode 100644 index 0000000000..869bf0d84d --- /dev/null +++ b/openstack/loadbalancer/v2/availabilityzoneprofiles/requests.go @@ -0,0 +1,145 @@ +package availabilityzoneprofiles + +import ( + "context" + + "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/pagination" +) + +// ListOptsBuilder allows extensions to add additional parameters to the +// List request. +type ListOptsBuilder interface { + ToAvailabilityZoneProfileListQuery() (string, error) +} + +// ListOpts allows to manage the output of the request. +type ListOpts struct { + // The name of the availability zone profile to filter by. + Name string `q:"name"` + // The provider name of the availability zone profile to filter by. + ProviderName string `q:"provider_name"` + // The fields that you want the server to return + Fields []string `q:"fields"` +} + +// ToAvailabilityZoneProfileListQuery formats a ListOpts into a query string. +func (opts ListOpts) ToAvailabilityZoneProfileListQuery() (string, error) { + q, err := gophercloud.BuildQueryString(opts) + return q.String(), err +} + +// List returns a Pager which allows you to iterate over a collection of +// AvailabilityZoneProfiles. It accepts a ListOpts struct, which allows you to +// filter and sort the returned collection for greater efficiency. +func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { + url := rootURL(c) + if opts != nil { + query, err := opts.ToAvailabilityZoneProfileListQuery() + if err != nil { + return pagination.Pager{Err: err} + } + url += query + } + return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page { + return AvailabilityZoneProfilePage{pagination.LinkedPageBase{PageResult: r}} + }) +} + +// CreateOptsBuilder allows extensions to add additional parameters to the +// Create request. +type CreateOptsBuilder interface { + ToAvailabilityZoneProfileCreateMap() (map[string]any, error) +} + +// CreateOpts is the common options struct used in this package's create +// operation. +type CreateOpts struct { + // Human-readable name for the avaialability zone profile. + // Does not have to be unique. + Name string `json:"name" required:"true"` + + // Providing the name of the provider supported by the Octavia installation. + ProviderName string `json:"provider_name" required:"true"` + + // Providing the json string containing the availability zone metadata. + AvailabilityZoneData string `json:"availability_zone_data" required:"true"` +} + +// ToAvailabilityZoneProfileCreateMap builds a request body from CreateOpts. +func (opts CreateOpts) ToAvailabilityZoneProfileCreateMap() (map[string]any, error) { + return gophercloud.BuildRequestBody(opts, "availability_zone_profile") +} + +// Create is and operation which add a new AvailabilityZoneProfile into the database. +// CreateResult will be returned. +func Create(ctx context.Context, c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { + b, err := opts.ToAvailabilityZoneProfileCreateMap() + if err != nil { + r.Err = err + return + } + resp, err := c.Post(ctx, rootURL(c), b, &r.Body, nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + +// Get retrieves a particular AvailabilityZoneProfile based on its unique ID. +func Get(ctx context.Context, c *gophercloud.ServiceClient, id string) (r GetResult) { + resp, err := c.Get(ctx, resourceURL(c, id), &r.Body, nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + +// UpdateOptsBuilder allows extensions to add additional parameters to the +// update request. +type UpdateOptsBuilder interface { + ToAvailabiltyZoneProfileUpdateMap() (map[string]any, error) +} + +// UpdateOpts is the common options struct used in this package's update +// operation. +type UpdateOpts struct { + // Human-readable name for the availability zone profile. + // Does not have to be unique. + Name *string `json:"name,omitempty"` + + // Providing the name of the provider supported by the Octavia installation. + ProviderName *string `json:"provider_name,omitempty"` + + // Providing the json string containing the availability zone metadata. + AvailabiltyZoneData *string `json:"availability_zone_data,omitempty"` +} + +// ToAvailabiltyZoneProfileUpdateMap builds a request body from UpdateOpts. +func (opts UpdateOpts) ToAvailabiltyZoneProfileUpdateMap() (map[string]any, error) { + b, err := gophercloud.BuildRequestBody(opts, "availability_zone_profile") + if err != nil { + return nil, err + } + + return b, nil +} + +// Update is an operation which modifies the attributes of the specified +// AvailabilityZoneProfile. +func Update(ctx context.Context, c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) { + b, err := opts.ToAvailabiltyZoneProfileUpdateMap() + if err != nil { + r.Err = err + return + } + resp, err := c.Put(ctx, resourceURL(c, id), b, &r.Body, &gophercloud.RequestOpts{ + OkCodes: []int{200, 202}, + }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + +// Delete will permanently delete a particular AvailabiltyZoneProfile based on +// its unique ID. +func Delete(ctx context.Context, c *gophercloud.ServiceClient, id string) (r DeleteResult) { + resp, err := c.Delete(ctx, resourceURL(c, id), nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} diff --git a/openstack/loadbalancer/v2/availabilityzoneprofiles/results.go b/openstack/loadbalancer/v2/availabilityzoneprofiles/results.go new file mode 100644 index 0000000000..b002ba9ad0 --- /dev/null +++ b/openstack/loadbalancer/v2/availabilityzoneprofiles/results.go @@ -0,0 +1,96 @@ +package availabilityzoneprofiles + +import ( + "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/pagination" +) + +type AvailabilityZoneProfile struct { + // The unique ID for the AvailabilityZoneProfile + ID string `json:"id"` + + // Human-readable name for the AvailabilityZoneProfile. + // Does not have to be unique. + Name string `json:"name"` + + // Name of the provider + ProviderName string `json:"provider_name"` + + // Availability zone data + AvailabilityZoneData string `json:"availability_zone_data"` +} + +// AvailabilityZoneProfile is the page returned by a pager when traversing +// over a collection of profiles. +type AvailabilityZoneProfilePage struct { + pagination.LinkedPageBase +} + +// NextPageURL is invoked when a paginated collection of profiles has +// reached the end of a page and the pager seeks to traverse over a new one. +// In order to do this, it needs to construct the next page's URL. +func (r AvailabilityZoneProfilePage) NextPageURL(endpointURL string) (string, error) { + var s struct { + Links []gophercloud.Link `json:"availabilityzoneprofiles_links"` + } + err := r.ExtractInto(&s) + if err != nil { + return "", err + } + return gophercloud.ExtractNextURL(s.Links) +} + +// IsEmpty checks whether a AvailabilityZoneProfilePage struct is empty. +func (r AvailabilityZoneProfilePage) IsEmpty() (bool, error) { + is, err := ExtractAvailabilityZoneProfiles(r) + return len(is) == 0, err +} + +// ExtractAvailabilityZoneProfiles accepts a Page struct, specifically a +// AvailabilityZoneProfilePage struct, and extracts the elements into a slice +// of Flavor structs. In other words, a generic collection is mapped into a +// relevant slice. +func ExtractAvailabilityZoneProfiles(r pagination.Page) ([]AvailabilityZoneProfile, error) { + var s struct { + AvailabilityZoneProfiles []AvailabilityZoneProfile `json:"availability_zone_profiles"` + } + err := (r.(AvailabilityZoneProfilePage)).ExtractInto(&s) + return s.AvailabilityZoneProfiles, err +} + +type commonResult struct { + gophercloud.Result +} + +// Extract is a function that accepts a result and extracts a flavor. +func (r commonResult) Extract() (*AvailabilityZoneProfile, error) { + var s struct { + AvailabilityZoneProfile *AvailabilityZoneProfile `json:"availability_zone_profile"` + } + err := r.ExtractInto(&s) + return s.AvailabilityZoneProfile, err +} + +// CreateResult represents the result of a create operation. Call its Extract +// method to interpret it as a Flavor. +type CreateResult struct { + commonResult +} + +// GetResult represents the result of a get operation. Call its Extract +// method to interpret it as a Flavor. +type GetResult struct { + commonResult +} + +// UpdateResult represents the result of an update operation. Call its Extract +// method to interpret it as a Flavor. +type UpdateResult struct { + commonResult +} + +// DeleteResult represents the result of a delete operation. Call its +// ExtractErr method to determine if the request succeeded or failed. +type DeleteResult struct { + gophercloud.ErrResult +} diff --git a/openstack/loadbalancer/v2/availabilityzoneprofiles/testing/doc.go b/openstack/loadbalancer/v2/availabilityzoneprofiles/testing/doc.go new file mode 100644 index 0000000000..7603f836a0 --- /dev/null +++ b/openstack/loadbalancer/v2/availabilityzoneprofiles/testing/doc.go @@ -0,0 +1 @@ +package testing diff --git a/openstack/loadbalancer/v2/availabilityzoneprofiles/testing/fixtures.go b/openstack/loadbalancer/v2/availabilityzoneprofiles/testing/fixtures.go new file mode 100644 index 0000000000..873bd52244 --- /dev/null +++ b/openstack/loadbalancer/v2/availabilityzoneprofiles/testing/fixtures.go @@ -0,0 +1,159 @@ +package testing + +import ( + "fmt" + "net/http" + "testing" + + "github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/availabilityzoneprofiles" + + th "github.com/gophercloud/gophercloud/v2/testhelper" + "github.com/gophercloud/gophercloud/v2/testhelper/client" +) + +const AvailabilityZoneProfilesListBody = ` +{ + "availability_zone_profiles": [ + { + "id": "1d334061-d807-4997-8f34-9fe428ba37df", + "name": "availability-zone-profile-first", + "provider_name": "amphora", + "availability_zone_data": "{\"compute_zone\": \"nova\", \"volume_zone\": \"nova\"}" + }, + { + "id": "56f45d00-86e4-4bea-8525-19e835776c4e", + "name": "availability-zone-profile-second", + "provider_name": "amphora", + "availability_zone_data": "{\"compute_zone\": \"not_nova\", \"volume_zone\": \"not_nova\"}" + } + ] +} +` + +const SingleAvailabilityZoneProfileBody = ` +{ + "availability_zone_profile": { + "id": "13be083b-f502-426e-8500-07600f98b91b", + "name": "availability-zone-profile", + "provider_name": "amphora", + "availability_zone_data": "{\"compute_zone\": \"nova\", \"volume_zone\": \"nova\"}" + } +} +` + +const PostUpdateAvailabilityZoneFlavorBody = ` +{ + "availability_zone_profile": { + "id": "13be083b-f502-426e-8500-07600f98b91b", + "name": "availability-zone-profile-updated", + "provider_name": "amphora", + "availability_zone_data": "{\"compute_zone\": \"nova\", \"volume_zone\": \"nova\"}" + } +} +` + +var ( + AvailabilityZoneProfileSingle = availabilityzoneprofiles.AvailabilityZoneProfile{ + ID: "1d334061-d807-4997-8f34-9fe428ba37df", + Name: "availability-zone-profile-first", + ProviderName: "amphora", + AvailabilityZoneData: "{\"compute_zone\": \"nova\", \"volume_zone\": \"nova\"}", + } + + AvailabilityZoneProfileAct = availabilityzoneprofiles.AvailabilityZoneProfile{ + ID: "56f45d00-86e4-4bea-8525-19e835776c4e", + Name: "availability-zone-profile-second", + ProviderName: "amphora", + AvailabilityZoneData: "{\"compute_zone\": \"not_nova\", \"volume_zone\": \"not_nova\"}", + } + + AvailabilityZoneProfileDb = availabilityzoneprofiles.AvailabilityZoneProfile{ + ID: "13be083b-f502-426e-8500-07600f98b91b", + Name: "availability-zone-profile", + ProviderName: "amphora", + AvailabilityZoneData: "{\"compute_zone\": \"nova\", \"volume_zone\": \"nova\"}", + } + + AvailabilityZoneProfileUpdated = availabilityzoneprofiles.AvailabilityZoneProfile{ + ID: "13be083b-f502-426e-8500-07600f98b91b", + Name: "availability-zone-profile-updated", + ProviderName: "amphora", + AvailabilityZoneData: "{\"compute_zone\": \"nova\", \"volume_zone\": \"nova\"}", + } +) + +func HandleAvailabilityZoneProfileListSuccessfully(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/v2.0/lbaas/availabilityzoneprofiles", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + if err := r.ParseForm(); err != nil { + t.Errorf("Failed to parse request form %v", err) + } + marker := r.Form.Get("marker") + switch marker { + case "": + fmt.Fprint(w, AvailabilityZoneProfilesListBody) + case "56f45d00-86e4-4bea-8525-19e835776c4e": + fmt.Fprint(w, `{ "availability_zone_profiles": [] }`) + default: + t.Fatalf("/v2.0/lbaas/availabilityzoneprofiles invoked with unexpected marker=[%s]", marker) + } + }) +} + +func HandleAvailabilityZoneProfileCreationSuccessfully(t *testing.T, fakeServer th.FakeServer, response string) { + fakeServer.Mux.HandleFunc("/v2.0/lbaas/availabilityzoneprofiles", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.TestJSONRequest(t, r, `{ + "availability_zone_profile": { + "name": "availability-zone-profile", + "provider_name": "amphora", + "availability_zone_data": "{\"compute_zone\": \"nova\", \"volume_zone\": \"nova\"}" + } + }`) + + w.WriteHeader(http.StatusAccepted) + w.Header().Add("Content-Type", "application/json") + fmt.Fprint(w, response) + }) +} + +func HandleAvailabilityZoneProfileGetSuccessfully(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/v2.0/lbaas/availabilityzoneprofiles/13be083b-f502-426e-8500-07600f98b91b", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.TestHeader(t, r, "Accept", "application/json") + + fmt.Fprint(w, SingleAvailabilityZoneProfileBody) + }) +} + +func HandleAvailabilityZoneProfileDeletionSuccessfully(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/v2.0/lbaas/availabilityzoneprofiles/13be083b-f502-426e-8500-07600f98b91b", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "DELETE") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.WriteHeader(http.StatusNoContent) + }) +} + +func HandleAvailabilityZoneProfileUpdateSuccessfully(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/v2.0/lbaas/availabilityzoneprofiles/dcd65be5-f117-4260-ab3d-b32cc5bd1272", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "PUT") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.TestHeader(t, r, "Accept", "application/json") + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestJSONRequest(t, r, `{ + "availability_zone_profile": { + "name": "availability-zone-profile-updated", + "provider_name": "amphora", + "availability_zone_data": "{\"compute_zone\": \"nova\", \"volume_zone\": \"nova\"}" + } + }`) + + fmt.Fprint(w, PostUpdateAvailabilityZoneFlavorBody) + }) +} diff --git a/openstack/loadbalancer/v2/availabilityzoneprofiles/testing/requests_test.go b/openstack/loadbalancer/v2/availabilityzoneprofiles/testing/requests_test.go new file mode 100644 index 0000000000..afea3921fb --- /dev/null +++ b/openstack/loadbalancer/v2/availabilityzoneprofiles/testing/requests_test.go @@ -0,0 +1,122 @@ +package testing + +import ( + "context" + "testing" + + "github.com/gophercloud/gophercloud/v2/internal/ptr" + "github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/availabilityzoneprofiles" + "github.com/gophercloud/gophercloud/v2/pagination" + + fake "github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/testhelper" + th "github.com/gophercloud/gophercloud/v2/testhelper" +) + +func TestListAvailabiltyZoneProfiles(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + HandleAvailabilityZoneProfileListSuccessfully(t, fakeServer) + + pages := 0 + err := availabilityzoneprofiles.List(fake.ServiceClient(fakeServer), availabilityzoneprofiles.ListOpts{}).EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) { + pages++ + + actual, err := availabilityzoneprofiles.ExtractAvailabilityZoneProfiles(page) + if err != nil { + return false, err + } + + if len(actual) != 2 { + t.Fatalf("Expected 2 avaialbility zone profiles, got %d", len(actual)) + } + th.CheckDeepEquals(t, AvailabilityZoneProfileSingle, actual[0]) + th.CheckDeepEquals(t, AvailabilityZoneProfileAct, actual[1]) + + return true, nil + }) + + th.AssertNoErr(t, err) + + if pages != 1 { + t.Errorf("Expected 1 page, saw %d", pages) + } +} + +func TestListAllAvailabilityZoneProfiles(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + HandleAvailabilityZoneProfileListSuccessfully(t, fakeServer) + + allPages, err := availabilityzoneprofiles.List(fake.ServiceClient(fakeServer), availabilityzoneprofiles.ListOpts{}).AllPages(context.TODO()) + th.AssertNoErr(t, err) + actual, err := availabilityzoneprofiles.ExtractAvailabilityZoneProfiles(allPages) + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, AvailabilityZoneProfileSingle, actual[0]) + th.CheckDeepEquals(t, AvailabilityZoneProfileAct, actual[1]) +} + +func TestCreateAvailabilityZoneProfile(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + HandleAvailabilityZoneProfileCreationSuccessfully(t, fakeServer, SingleAvailabilityZoneProfileBody) + + actual, err := availabilityzoneprofiles.Create(context.TODO(), fake.ServiceClient(fakeServer), availabilityzoneprofiles.CreateOpts{ + Name: "availability-zone-profile", + ProviderName: "amphora", + AvailabilityZoneData: "{\"compute_zone\": \"nova\", \"volume_zone\": \"nova\"}", + }).Extract() + th.AssertNoErr(t, err) + + th.CheckDeepEquals(t, AvailabilityZoneProfileDb, *actual) +} + +func TestRequiredCreateOpts(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + res := availabilityzoneprofiles.Create(context.TODO(), fake.ServiceClient(fakeServer), availabilityzoneprofiles.CreateOpts{}) + if res.Err == nil { + t.Fatalf("Expected error, got none") + } +} + +func TestGetAvailabilityZoneProfiles(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + HandleAvailabilityZoneProfileGetSuccessfully(t, fakeServer) + + client := fake.ServiceClient(fakeServer) + actual, err := availabilityzoneprofiles.Get(context.TODO(), client, "13be083b-f502-426e-8500-07600f98b91b").Extract() + if err != nil { + t.Fatalf("Unexpected Get error: %v", err) + } + + th.CheckDeepEquals(t, AvailabilityZoneProfileDb, *actual) +} + +func TestDeleteAvailabilityZoneProfile(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + HandleAvailabilityZoneProfileDeletionSuccessfully(t, fakeServer) + + res := availabilityzoneprofiles.Delete(context.TODO(), fake.ServiceClient(fakeServer), "13be083b-f502-426e-8500-07600f98b91b") + th.AssertNoErr(t, res.Err) +} + +func TestUpdateAvailabililtyZoneProfile(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + HandleAvailabilityZoneProfileUpdateSuccessfully(t, fakeServer) + + client := fake.ServiceClient(fakeServer) + actual, err := availabilityzoneprofiles.Update(context.TODO(), client, "dcd65be5-f117-4260-ab3d-b32cc5bd1272", availabilityzoneprofiles.UpdateOpts{ + Name: ptr.To("availability-zone-profile-updated"), + ProviderName: ptr.To("amphora"), + AvailabiltyZoneData: ptr.To(`{"compute_zone": "nova", "volume_zone": "nova"}`), + }).Extract() + if err != nil { + t.Fatalf("Unexpected Update error: %v", err) + } + + th.CheckDeepEquals(t, AvailabilityZoneProfileUpdated, *actual) +} diff --git a/openstack/loadbalancer/v2/availabilityzoneprofiles/urls.go b/openstack/loadbalancer/v2/availabilityzoneprofiles/urls.go new file mode 100644 index 0000000000..e2321402a3 --- /dev/null +++ b/openstack/loadbalancer/v2/availabilityzoneprofiles/urls.go @@ -0,0 +1,16 @@ +package availabilityzoneprofiles + +import "github.com/gophercloud/gophercloud/v2" + +const ( + rootPath = "lbaas" + resourcePath = "availabilityzoneprofiles" +) + +func rootURL(c *gophercloud.ServiceClient) string { + return c.ServiceURL(rootPath, resourcePath) +} + +func resourceURL(c *gophercloud.ServiceClient, id string) string { + return c.ServiceURL(rootPath, resourcePath, id) +} From fd88cf1a5ea1052aab22247fdc7391125a8b6482 Mon Sep 17 00:00:00 2001 From: Konstantin Eremin Date: Wed, 24 Dec 2025 01:34:31 +0300 Subject: [PATCH 298/429] Fix syntax --- .../openstack/loadbalancer/v2/availabilityzoneprofiles_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/acceptance/openstack/loadbalancer/v2/availabilityzoneprofiles_test.go b/internal/acceptance/openstack/loadbalancer/v2/availabilityzoneprofiles_test.go index fc991caa2c..27483926ed 100644 --- a/internal/acceptance/openstack/loadbalancer/v2/availabilityzoneprofiles_test.go +++ b/internal/acceptance/openstack/loadbalancer/v2/availabilityzoneprofiles_test.go @@ -1,4 +1,4 @@ -//go:build acceptance || networking || loadbalancer || flavorprofiles +//go:build acceptance || networking || loadbalancer || availabilityzoneprofiles package v2 From 7dedf220109e7c1fd53df1dff5015d4faeee7dbe Mon Sep 17 00:00:00 2001 From: Konstantin Eremin Date: Thu, 25 Dec 2025 16:50:36 +0300 Subject: [PATCH 299/429] Add missing methods, fix typo --- .../v2/availabilityzoneprofiles_test.go | 4 +-- .../openstack/loadbalancer/v2/loadbalancer.go | 35 +++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/internal/acceptance/openstack/loadbalancer/v2/availabilityzoneprofiles_test.go b/internal/acceptance/openstack/loadbalancer/v2/availabilityzoneprofiles_test.go index 27483926ed..03707128cf 100644 --- a/internal/acceptance/openstack/loadbalancer/v2/availabilityzoneprofiles_test.go +++ b/internal/acceptance/openstack/loadbalancer/v2/availabilityzoneprofiles_test.go @@ -21,7 +21,7 @@ func TestAvailabilityZoneProfilesList(t *testing.T) { allPages, err := availabilityzoneprofiles.List(client, nil).AllPages(context.TODO()) th.AssertNoErr(t, err) - allAvailabilityZoneProfiles, err := availabilityzoneprofiles.ExtractFlavorProfiles(allPages) + allAvailabilityZoneProfiles, err := availabilityzoneprofiles.ExtractAvailabilityZones(allPages) th.AssertNoErr(t, err) for _, availabilityzoneprofile := range allAvailabilityZoneProfiles { @@ -33,7 +33,7 @@ func TestAvailabilityZoneProfilesCRUD(t *testing.T) { lbClient, err := clients.NewLoadBalancerV2Client() th.AssertNoErr(t, err) - availabilityZoneProfile, err := CreateAvailabilityZonerProfile(t, lbClient) + availabilityZoneProfile, err := CreateAvailabilityZoneProfile(t, lbClient) th.AssertNoErr(t, err) defer DeleteAvailabilityZoneProfile(t, lbClient, availabilityZoneProfile) diff --git a/internal/acceptance/openstack/loadbalancer/v2/loadbalancer.go b/internal/acceptance/openstack/loadbalancer/v2/loadbalancer.go index cc62ba626e..714f4b8e01 100644 --- a/internal/acceptance/openstack/loadbalancer/v2/loadbalancer.go +++ b/internal/acceptance/openstack/loadbalancer/v2/loadbalancer.go @@ -11,6 +11,7 @@ import ( "github.com/gophercloud/gophercloud/v2/internal/acceptance/clients" "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" "github.com/gophercloud/gophercloud/v2/internal/ptr" + "github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/availabilityzoneprofiles" "github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/flavorprofiles" "github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/flavors" "github.com/gophercloud/gophercloud/v2/openstack/loadbalancer/v2/l7policies" @@ -761,3 +762,37 @@ func DeleteFlavor(t *testing.T, client *gophercloud.ServiceClient, flavor *flavo t.Logf("Successfully deleted flavor %s", flavor.Name) } + +func CreateAvailabilityZoneProfile(t *testing.T, client *gophercloud.ServiceClient) (*availabilityzoneprofiles.AvailabilityZoneProfile, error) { + availabilityZoneProfileName := tools.RandomString("TESTACCT-", 8) + availabilityZoneProfileDriver := "amphora" + availabilityZoneData := "{\"compute_zone\": \"not_nova\", \"volume_zone\": \"not_nova\"}" + + createOpts := availabilityzoneprofiles.CreateOpts{ + Name: availabilityZoneProfileName, + ProviderName: availabilityZoneProfileDriver, + AvailabilityZoneData: availabilityZoneData, + } + + availabilityZoneProfile, err := availabilityzoneprofiles.Create(context.TODO(), client, createOpts).Extract() + if err != nil { + return availabilityZoneProfile, err + } + + t.Logf("Successfully created availabilityzoneprofile %s", availabilityZoneProfileName) + + th.AssertEquals(t, availabilityZoneProfileName, availabilityZoneProfile.Name) + th.AssertEquals(t, availabilityZoneProfileDriver, availabilityZoneProfile.ProviderName) + th.AssertEquals(t, availabilityZoneData, availabilityZoneProfile.AvailabilityZoneData) + + return availabilityZoneProfile, nil +} + +func DeleteAvailabilityZoneProfile(t *testing.T, client *gophercloud.ServiceClient, availabilityZoneProfile *availabilityzoneprofiles.AvailabilityZoneProfile) { + err := availabilityzoneprofiles.Delete(context.TODO(), client, availabilityZoneProfile.ID).ExtractErr() + if err != nil { + t.Fatalf("Unable to delete availabilityzoneprofile: %v", err) + } + + t.Logf("Successfully deleted availabilityzoneprofile %s", availabilityZoneProfile.Name) +} From c2f47ec499148dd7ab722f9d870cf14050c07bf8 Mon Sep 17 00:00:00 2001 From: Konstantin Eremin Date: Thu, 25 Dec 2025 16:56:45 +0300 Subject: [PATCH 300/429] Fix typo --- .../openstack/loadbalancer/v2/availabilityzoneprofiles_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/acceptance/openstack/loadbalancer/v2/availabilityzoneprofiles_test.go b/internal/acceptance/openstack/loadbalancer/v2/availabilityzoneprofiles_test.go index 03707128cf..238647a3b0 100644 --- a/internal/acceptance/openstack/loadbalancer/v2/availabilityzoneprofiles_test.go +++ b/internal/acceptance/openstack/loadbalancer/v2/availabilityzoneprofiles_test.go @@ -21,7 +21,7 @@ func TestAvailabilityZoneProfilesList(t *testing.T) { allPages, err := availabilityzoneprofiles.List(client, nil).AllPages(context.TODO()) th.AssertNoErr(t, err) - allAvailabilityZoneProfiles, err := availabilityzoneprofiles.ExtractAvailabilityZones(allPages) + allAvailabilityZoneProfiles, err := availabilityzoneprofiles.ExtractAvailabilityZoneProfiles(allPages) th.AssertNoErr(t, err) for _, availabilityzoneprofile := range allAvailabilityZoneProfiles { From b6e7b17aa6c75f65ee5d3b1b721eabb752352faa Mon Sep 17 00:00:00 2001 From: Konstantin Eremin Date: Thu, 25 Dec 2025 17:22:44 +0300 Subject: [PATCH 301/429] Fix fixtures data --- internal/acceptance/openstack/loadbalancer/v2/loadbalancer.go | 2 +- .../v2/availabilityzoneprofiles/testing/fixtures.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/acceptance/openstack/loadbalancer/v2/loadbalancer.go b/internal/acceptance/openstack/loadbalancer/v2/loadbalancer.go index 714f4b8e01..bdbe9ddf5a 100644 --- a/internal/acceptance/openstack/loadbalancer/v2/loadbalancer.go +++ b/internal/acceptance/openstack/loadbalancer/v2/loadbalancer.go @@ -766,7 +766,7 @@ func DeleteFlavor(t *testing.T, client *gophercloud.ServiceClient, flavor *flavo func CreateAvailabilityZoneProfile(t *testing.T, client *gophercloud.ServiceClient) (*availabilityzoneprofiles.AvailabilityZoneProfile, error) { availabilityZoneProfileName := tools.RandomString("TESTACCT-", 8) availabilityZoneProfileDriver := "amphora" - availabilityZoneData := "{\"compute_zone\": \"not_nova\", \"volume_zone\": \"not_nova\"}" + availabilityZoneData := "{\"compute_zone\": \"nova\", \"volume_zone\": \"nova\"}" createOpts := availabilityzoneprofiles.CreateOpts{ Name: availabilityZoneProfileName, diff --git a/openstack/loadbalancer/v2/availabilityzoneprofiles/testing/fixtures.go b/openstack/loadbalancer/v2/availabilityzoneprofiles/testing/fixtures.go index 873bd52244..1aebb02284 100644 --- a/openstack/loadbalancer/v2/availabilityzoneprofiles/testing/fixtures.go +++ b/openstack/loadbalancer/v2/availabilityzoneprofiles/testing/fixtures.go @@ -24,7 +24,7 @@ const AvailabilityZoneProfilesListBody = ` "id": "56f45d00-86e4-4bea-8525-19e835776c4e", "name": "availability-zone-profile-second", "provider_name": "amphora", - "availability_zone_data": "{\"compute_zone\": \"not_nova\", \"volume_zone\": \"not_nova\"}" + "availability_zone_data": "{\"compute_zone\": \"nova\", \"volume_zone\": \"nova\"}" } ] } @@ -64,7 +64,7 @@ var ( ID: "56f45d00-86e4-4bea-8525-19e835776c4e", Name: "availability-zone-profile-second", ProviderName: "amphora", - AvailabilityZoneData: "{\"compute_zone\": \"not_nova\", \"volume_zone\": \"not_nova\"}", + AvailabilityZoneData: "{\"compute_zone\": \"nova\", \"volume_zone\": \"nova\"}", } AvailabilityZoneProfileDb = availabilityzoneprofiles.AvailabilityZoneProfile{ From d761fb88339840dd9cefcb0a18199d6f7f7331dc Mon Sep 17 00:00:00 2001 From: Konstantin Eremin Date: Thu, 25 Dec 2025 18:18:06 +0300 Subject: [PATCH 302/429] Remove availability zone profile volume_zone, only master --- .../openstack/loadbalancer/v2/loadbalancer.go | 2 +- .../v2/availabilityzoneprofiles/doc.go | 2 +- .../testing/fixtures.go | 20 +++++++++---------- .../testing/requests_test.go | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/internal/acceptance/openstack/loadbalancer/v2/loadbalancer.go b/internal/acceptance/openstack/loadbalancer/v2/loadbalancer.go index bdbe9ddf5a..8490d27f36 100644 --- a/internal/acceptance/openstack/loadbalancer/v2/loadbalancer.go +++ b/internal/acceptance/openstack/loadbalancer/v2/loadbalancer.go @@ -766,7 +766,7 @@ func DeleteFlavor(t *testing.T, client *gophercloud.ServiceClient, flavor *flavo func CreateAvailabilityZoneProfile(t *testing.T, client *gophercloud.ServiceClient) (*availabilityzoneprofiles.AvailabilityZoneProfile, error) { availabilityZoneProfileName := tools.RandomString("TESTACCT-", 8) availabilityZoneProfileDriver := "amphora" - availabilityZoneData := "{\"compute_zone\": \"nova\", \"volume_zone\": \"nova\"}" + availabilityZoneData := "{\"compute_zone\": \"nova\"}" createOpts := availabilityzoneprofiles.CreateOpts{ Name: availabilityZoneProfileName, diff --git a/openstack/loadbalancer/v2/availabilityzoneprofiles/doc.go b/openstack/loadbalancer/v2/availabilityzoneprofiles/doc.go index a6a47f205f..30a3223da2 100644 --- a/openstack/loadbalancer/v2/availabilityzoneprofiles/doc.go +++ b/openstack/loadbalancer/v2/availabilityzoneprofiles/doc.go @@ -25,7 +25,7 @@ Example to Create a AvailabilityZoneProfile createOpts := availabilityzoneprofiles.CreateOpts{ Name: "availability-zone-profile", ProviderName: "amphora", - AvailabilityZoneData: "{\"compute_zone\": \"nova\", \"volume_zone\": \"nova\"}", + AvailabilityZoneData: "{\"compute_zone\": \"nova\"}", } availabilityZoneProfile, err := availabilityzoneprofiles.Create(context.TODO(), octaviaClient, createOpts).Extract() diff --git a/openstack/loadbalancer/v2/availabilityzoneprofiles/testing/fixtures.go b/openstack/loadbalancer/v2/availabilityzoneprofiles/testing/fixtures.go index 1aebb02284..b60ce711ac 100644 --- a/openstack/loadbalancer/v2/availabilityzoneprofiles/testing/fixtures.go +++ b/openstack/loadbalancer/v2/availabilityzoneprofiles/testing/fixtures.go @@ -18,13 +18,13 @@ const AvailabilityZoneProfilesListBody = ` "id": "1d334061-d807-4997-8f34-9fe428ba37df", "name": "availability-zone-profile-first", "provider_name": "amphora", - "availability_zone_data": "{\"compute_zone\": \"nova\", \"volume_zone\": \"nova\"}" + "availability_zone_data": "{\"compute_zone\": \"nova\"}" }, { "id": "56f45d00-86e4-4bea-8525-19e835776c4e", "name": "availability-zone-profile-second", "provider_name": "amphora", - "availability_zone_data": "{\"compute_zone\": \"nova\", \"volume_zone\": \"nova\"}" + "availability_zone_data": "{\"compute_zone\": \"nova\"}" } ] } @@ -36,7 +36,7 @@ const SingleAvailabilityZoneProfileBody = ` "id": "13be083b-f502-426e-8500-07600f98b91b", "name": "availability-zone-profile", "provider_name": "amphora", - "availability_zone_data": "{\"compute_zone\": \"nova\", \"volume_zone\": \"nova\"}" + "availability_zone_data": "{\"compute_zone\": \"nova\"}" } } ` @@ -47,7 +47,7 @@ const PostUpdateAvailabilityZoneFlavorBody = ` "id": "13be083b-f502-426e-8500-07600f98b91b", "name": "availability-zone-profile-updated", "provider_name": "amphora", - "availability_zone_data": "{\"compute_zone\": \"nova\", \"volume_zone\": \"nova\"}" + "availability_zone_data": "{\"compute_zone\": \"nova\"}" } } ` @@ -57,28 +57,28 @@ var ( ID: "1d334061-d807-4997-8f34-9fe428ba37df", Name: "availability-zone-profile-first", ProviderName: "amphora", - AvailabilityZoneData: "{\"compute_zone\": \"nova\", \"volume_zone\": \"nova\"}", + AvailabilityZoneData: "{\"compute_zone\": \"nova\"}", } AvailabilityZoneProfileAct = availabilityzoneprofiles.AvailabilityZoneProfile{ ID: "56f45d00-86e4-4bea-8525-19e835776c4e", Name: "availability-zone-profile-second", ProviderName: "amphora", - AvailabilityZoneData: "{\"compute_zone\": \"nova\", \"volume_zone\": \"nova\"}", + AvailabilityZoneData: "{\"compute_zone\": \"nova\"}", } AvailabilityZoneProfileDb = availabilityzoneprofiles.AvailabilityZoneProfile{ ID: "13be083b-f502-426e-8500-07600f98b91b", Name: "availability-zone-profile", ProviderName: "amphora", - AvailabilityZoneData: "{\"compute_zone\": \"nova\", \"volume_zone\": \"nova\"}", + AvailabilityZoneData: "{\"compute_zone\": \"nova\"}", } AvailabilityZoneProfileUpdated = availabilityzoneprofiles.AvailabilityZoneProfile{ ID: "13be083b-f502-426e-8500-07600f98b91b", Name: "availability-zone-profile-updated", ProviderName: "amphora", - AvailabilityZoneData: "{\"compute_zone\": \"nova\", \"volume_zone\": \"nova\"}", + AvailabilityZoneData: "{\"compute_zone\": \"nova\"}", } ) @@ -111,7 +111,7 @@ func HandleAvailabilityZoneProfileCreationSuccessfully(t *testing.T, fakeServer "availability_zone_profile": { "name": "availability-zone-profile", "provider_name": "amphora", - "availability_zone_data": "{\"compute_zone\": \"nova\", \"volume_zone\": \"nova\"}" + "availability_zone_data": "{\"compute_zone\": \"nova\"}" } }`) @@ -150,7 +150,7 @@ func HandleAvailabilityZoneProfileUpdateSuccessfully(t *testing.T, fakeServer th "availability_zone_profile": { "name": "availability-zone-profile-updated", "provider_name": "amphora", - "availability_zone_data": "{\"compute_zone\": \"nova\", \"volume_zone\": \"nova\"}" + "availability_zone_data": "{\"compute_zone\": \"nova\"}" } }`) diff --git a/openstack/loadbalancer/v2/availabilityzoneprofiles/testing/requests_test.go b/openstack/loadbalancer/v2/availabilityzoneprofiles/testing/requests_test.go index afea3921fb..7ce47457b6 100644 --- a/openstack/loadbalancer/v2/availabilityzoneprofiles/testing/requests_test.go +++ b/openstack/loadbalancer/v2/availabilityzoneprofiles/testing/requests_test.go @@ -63,7 +63,7 @@ func TestCreateAvailabilityZoneProfile(t *testing.T) { actual, err := availabilityzoneprofiles.Create(context.TODO(), fake.ServiceClient(fakeServer), availabilityzoneprofiles.CreateOpts{ Name: "availability-zone-profile", ProviderName: "amphora", - AvailabilityZoneData: "{\"compute_zone\": \"nova\", \"volume_zone\": \"nova\"}", + AvailabilityZoneData: "{\"compute_zone\": \"nova\"}", }).Extract() th.AssertNoErr(t, err) @@ -112,7 +112,7 @@ func TestUpdateAvailabililtyZoneProfile(t *testing.T) { actual, err := availabilityzoneprofiles.Update(context.TODO(), client, "dcd65be5-f117-4260-ab3d-b32cc5bd1272", availabilityzoneprofiles.UpdateOpts{ Name: ptr.To("availability-zone-profile-updated"), ProviderName: ptr.To("amphora"), - AvailabiltyZoneData: ptr.To(`{"compute_zone": "nova", "volume_zone": "nova"}`), + AvailabiltyZoneData: ptr.To(`{"compute_zone": "nova"}`), }).Extract() if err != nil { t.Fatalf("Unexpected Update error: %v", err) From d2e0b940a8194903f4bda421348a2740838d50fb Mon Sep 17 00:00:00 2001 From: Winicius Silva Date: Fri, 12 Dec 2025 11:18:21 -0300 Subject: [PATCH 303/429] identity.v3.Endpoint: make name as optional on creation --- openstack/identity/v3/endpoints/requests.go | 2 +- openstack/identity/v3/endpoints/testing/requests_test.go | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/openstack/identity/v3/endpoints/requests.go b/openstack/identity/v3/endpoints/requests.go index 45893aa3c6..8c08542848 100644 --- a/openstack/identity/v3/endpoints/requests.go +++ b/openstack/identity/v3/endpoints/requests.go @@ -26,7 +26,7 @@ type CreateOpts struct { Enabled *bool `json:"enabled,omitempty"` // Name is the name of the Endpoint. - Name string `json:"name" required:"true"` + Name string `json:"name,omitempty"` // Region is the region the Endpoint is located in. // This field can be omitted or left as a blank string. diff --git a/openstack/identity/v3/endpoints/testing/requests_test.go b/openstack/identity/v3/endpoints/testing/requests_test.go index 07798947c6..8e50467e25 100644 --- a/openstack/identity/v3/endpoints/testing/requests_test.go +++ b/openstack/identity/v3/endpoints/testing/requests_test.go @@ -23,7 +23,6 @@ func TestCreateSuccessful(t *testing.T) { th.TestJSONRequest(t, r, `{ "endpoint": { "interface": "public", - "name": "the-endiest-of-points", "region": "underground", "url": "https://1.2.3.4:9000/", "service_id": "asdfasdfasdfasdf", @@ -41,7 +40,6 @@ func TestCreateSuccessful(t *testing.T) { "links": { "self": "https://localhost:5000/v3/endpoints/12" }, - "name": "the-endiest-of-points", "region": "underground", "service_id": "asdfasdfasdfasdf", "url": "https://1.2.3.4:9000/", @@ -53,7 +51,6 @@ func TestCreateSuccessful(t *testing.T) { enabled := false actual, err := endpoints.Create(context.TODO(), client.ServiceClient(fakeServer), endpoints.CreateOpts{ Availability: gophercloud.AvailabilityPublic, - Name: "the-endiest-of-points", Region: "underground", URL: "https://1.2.3.4:9000/", ServiceID: "asdfasdfasdfasdf", @@ -65,7 +62,6 @@ func TestCreateSuccessful(t *testing.T) { expected := &endpoints.Endpoint{ ID: "12", Availability: gophercloud.AvailabilityPublic, - Name: "the-endiest-of-points", Enabled: false, Region: "underground", ServiceID: "asdfasdfasdfasdf", From 57d6a1259926cfdcd374e0a027b02f6a6e7b4a94 Mon Sep 17 00:00:00 2001 From: Winicius Silva Date: Wed, 7 Jan 2026 20:47:05 -0300 Subject: [PATCH 304/429] endpoint: add missing pointer to description on update --- internal/acceptance/openstack/identity/v3/endpoint_test.go | 5 +++-- openstack/identity/v3/endpoints/requests.go | 2 +- openstack/identity/v3/endpoints/testing/requests_test.go | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/internal/acceptance/openstack/identity/v3/endpoint_test.go b/internal/acceptance/openstack/identity/v3/endpoint_test.go index 7d9da99854..8140a7d4f9 100644 --- a/internal/acceptance/openstack/identity/v3/endpoint_test.go +++ b/internal/acceptance/openstack/identity/v3/endpoint_test.go @@ -129,14 +129,15 @@ func TestEndpointCRUD(t *testing.T) { tools.PrintResource(t, endpoint.URL) enabled = true + description := "" newEndpoint, err := endpoints.Update(context.TODO(), client, endpoint.ID, &endpoints.UpdateOpts{ Name: "new-endpoint", URL: "https://example-updated.com", - Description: "Updated Endpoint", + Description: &description, Enabled: &enabled, }).Extract() th.AssertNoErr(t, err) th.AssertEquals(t, newEndpoint.URL, "https://example-updated.com") - th.AssertEquals(t, newEndpoint.Description, "Updated Endpoint") + th.AssertEquals(t, newEndpoint.Description, description) } diff --git a/openstack/identity/v3/endpoints/requests.go b/openstack/identity/v3/endpoints/requests.go index 8c08542848..a5dca90a9d 100644 --- a/openstack/identity/v3/endpoints/requests.go +++ b/openstack/identity/v3/endpoints/requests.go @@ -134,7 +134,7 @@ type UpdateOpts struct { ServiceID string `json:"service_id,omitempty"` // Description is an updated description of the endpoint. - Description string `json:"description,omitempty"` + Description *string `json:"description,omitempty"` } // ToEndpointUpdateMap builds an update request body from the Update options. diff --git a/openstack/identity/v3/endpoints/testing/requests_test.go b/openstack/identity/v3/endpoints/testing/requests_test.go index 8e50467e25..5ffde6638c 100644 --- a/openstack/identity/v3/endpoints/testing/requests_test.go +++ b/openstack/identity/v3/endpoints/testing/requests_test.go @@ -232,10 +232,11 @@ func TestUpdateEndpoint(t *testing.T) { }) enabled := false + description := "Changed description" actual, err := endpoints.Update(context.TODO(), client.ServiceClient(fakeServer), "12", endpoints.UpdateOpts{ Name: "renamed", Region: "somewhere-else", - Description: "Changed description", + Description: &description, Enabled: &enabled, }).Extract() if err != nil { From 4f71add6750071a34d76f489519b9886a8d1232a Mon Sep 17 00:00:00 2001 From: MahnoorAsghar Date: Thu, 8 Jan 2026 13:58:44 +0100 Subject: [PATCH 305/429] Add PCIAddress field to baremetal InterfaceType --- openstack/baremetal/inventory/types.go | 1 + 1 file changed, 1 insertion(+) diff --git a/openstack/baremetal/inventory/types.go b/openstack/baremetal/inventory/types.go index 468f32a74f..98498d530d 100644 --- a/openstack/baremetal/inventory/types.go +++ b/openstack/baremetal/inventory/types.go @@ -24,6 +24,7 @@ type InterfaceType struct { Product string `json:"product"` SpeedMbps int `json:"speed_mbps"` Vendor string `json:"vendor"` + PCIAddress string `json:"pci_address"` } type MemoryType struct { From fd11834b3ee987379546a13f80458ffdb4bb13c2 Mon Sep 17 00:00:00 2001 From: Mohammed Al-Dokimi Date: Mon, 12 Jan 2026 17:24:03 +0000 Subject: [PATCH 306/429] networking/v2/layer3/routers: Add external gateways management Add support for managing external gateways on routers: * AddExternalGateways * UpdateExternalGateways * RemoveExternalGateways These operations extend router.external_gateway_info to support multiple external gateways on a single router. Ref: https://docs.openstack.org/api-ref/network/v2/index.html#add-external-gateways-to-router --- .../v2/extensions/layer3/routers_test.go | 91 ++++++++ .../v2/extensions/layer3/routers/doc.go | 68 ++++++ .../v2/extensions/layer3/routers/requests.go | 96 +++++++++ .../layer3/routers/testing/requests_test.go | 200 ++++++++++++++++++ .../v2/extensions/layer3/routers/urls.go | 12 ++ 5 files changed, 467 insertions(+) diff --git a/internal/acceptance/openstack/networking/v2/extensions/layer3/routers_test.go b/internal/acceptance/openstack/networking/v2/extensions/layer3/routers_test.go index 5930be2a1e..be275f2ce1 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/layer3/routers_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/layer3/routers_test.go @@ -4,9 +4,11 @@ package layer3 import ( "context" + "net/http" "strings" "testing" + "github.com/gophercloud/gophercloud/v2" "github.com/gophercloud/gophercloud/v2/internal/acceptance/clients" networking "github.com/gophercloud/gophercloud/v2/internal/acceptance/openstack/networking/v2" "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" @@ -281,3 +283,92 @@ func TestLayer3RouterRevision(t *testing.T) { th.AssertEquals(t, router.Name, newName) th.AssertEquals(t, router.Description, newDescription) } + +func TestLayer3RouterExternalGateways(t *testing.T) { + clients.RequireAdmin(t) + + client, err := clients.NewNetworkV2Client() + th.AssertNoErr(t, err) + + // Skip if the external-gateway-multihoming extension is not available + networking.RequireNeutronExtension(t, client, "external-gateway-multihoming") + + // Create a router with external gateway + router, err := CreateExternalRouter(t, client) + th.AssertNoErr(t, err) + defer DeleteRouter(t, client, router.ID) + + tools.PrintResource(t, router) + + choices, err := clients.AcceptanceTestChoicesFromEnv() + th.AssertNoErr(t, err) + + // Test AddExternalGateways + t.Logf("Attempting to add external gateways to router %s", router.ID) + + addOpts := routers.AddExternalGatewaysOpts{ + ExternalGateways: []routers.GatewayInfo{ + { + NetworkID: choices.ExternalNetworkID, + }, + }, + } + + updatedRouter, err := routers.AddExternalGateways(context.TODO(), client, router.ID, addOpts).Extract() + if err != nil { + // If we get a 404, the extension might not be fully functional + if gophercloud.ResponseCodeIs(err, http.StatusNotFound) { + t.Skipf("AddExternalGateways not supported: %v", err) + } + th.AssertNoErr(t, err) + } + + t.Logf("Successfully added external gateways to router %s", router.ID) + tools.PrintResource(t, updatedRouter) + + // Test UpdateExternalGateways + t.Logf("Attempting to update external gateways of router %s", router.ID) + + enableSNAT := true + updateOpts := routers.UpdateExternalGatewaysOpts{ + ExternalGateways: []routers.GatewayInfo{ + { + NetworkID: choices.ExternalNetworkID, + EnableSNAT: &enableSNAT, + }, + }, + } + + updatedRouter, err = routers.UpdateExternalGateways(context.TODO(), client, router.ID, updateOpts).Extract() + if err != nil { + if gophercloud.ResponseCodeIs(err, http.StatusNotFound) { + t.Skipf("UpdateExternalGateways not supported: %v", err) + } + th.AssertNoErr(t, err) + } + + t.Logf("Successfully updated external gateways of router %s", router.ID) + tools.PrintResource(t, updatedRouter) + + // Test RemoveExternalGateways + t.Logf("Attempting to remove external gateways from router %s", router.ID) + + removeOpts := routers.RemoveExternalGatewaysOpts{ + ExternalGateways: []routers.GatewayInfo{ + { + NetworkID: choices.ExternalNetworkID, + }, + }, + } + + updatedRouter, err = routers.RemoveExternalGateways(context.TODO(), client, router.ID, removeOpts).Extract() + if err != nil { + if gophercloud.ResponseCodeIs(err, http.StatusNotFound) { + t.Skipf("RemoveExternalGateways not supported: %v", err) + } + th.AssertNoErr(t, err) + } + + t.Logf("Successfully removed external gateways from router %s", router.ID) + tools.PrintResource(t, updatedRouter) +} diff --git a/openstack/networking/v2/extensions/layer3/routers/doc.go b/openstack/networking/v2/extensions/layer3/routers/doc.go index 42ccbcf7cf..4faa862fc1 100644 --- a/openstack/networking/v2/extensions/layer3/routers/doc.go +++ b/openstack/networking/v2/extensions/layer3/routers/doc.go @@ -135,5 +135,73 @@ Example to List an L3 agents for a Router for _, agent := range allL3Agents { fmt.Printf("%+v\n", agent) } + +Example to Add External Gateways to a Router + +This requires the external-gateway-multihoming extension. + + routerID := "4e8e5957-649f-477b-9e5b-f1f75b21c03c" + + addOpts := routers.AddExternalGatewaysOpts{ + ExternalGateways: []routers.GatewayInfo{ + { + NetworkID: "8ca37218-28ff-41cb-9b10-039601ea7e6b", + ExternalFixedIPs: []routers.ExternalFixedIP{ + {SubnetID: "ab561bc4-1a8e-48f2-9fbd-376fcb1a1def"}, + }, + }, + }, + } + + router, err := routers.AddExternalGateways(context.TODO(), networkClient, routerID, addOpts).Extract() + if err != nil { + panic(err) + } + +Example to Update External Gateways of a Router + +This requires the external-gateway-multihoming extension. + + routerID := "4e8e5957-649f-477b-9e5b-f1f75b21c03c" + + enableSNAT := true + updateOpts := routers.UpdateExternalGatewaysOpts{ + ExternalGateways: []routers.GatewayInfo{ + { + NetworkID: "8ca37218-28ff-41cb-9b10-039601ea7e6b", + EnableSNAT: &enableSNAT, + ExternalFixedIPs: []routers.ExternalFixedIP{ + {IPAddress: "192.0.2.17", SubnetID: "ab561bc4-1a8e-48f2-9fbd-376fcb1a1def"}, + }, + }, + }, + } + + router, err := routers.UpdateExternalGateways(context.TODO(), networkClient, routerID, updateOpts).Extract() + if err != nil { + panic(err) + } + +Example to Remove External Gateways from a Router + +This requires the external-gateway-multihoming extension. + + routerID := "4e8e5957-649f-477b-9e5b-f1f75b21c03c" + + removeOpts := routers.RemoveExternalGatewaysOpts{ + ExternalGateways: []routers.GatewayInfo{ + { + NetworkID: "8ca37218-28ff-41cb-9b10-039601ea7e6b", + ExternalFixedIPs: []routers.ExternalFixedIP{ + {IPAddress: "192.0.2.17", SubnetID: "ab561bc4-1a8e-48f2-9fbd-376fcb1a1def"}, + }, + }, + }, + } + + router, err := routers.RemoveExternalGateways(context.TODO(), networkClient, routerID, removeOpts).Extract() + if err != nil { + panic(err) + } */ package routers diff --git a/openstack/networking/v2/extensions/layer3/routers/requests.go b/openstack/networking/v2/extensions/layer3/routers/requests.go index def4699db3..3e49a30f10 100644 --- a/openstack/networking/v2/extensions/layer3/routers/requests.go +++ b/openstack/networking/v2/extensions/layer3/routers/requests.go @@ -282,3 +282,99 @@ func ListL3Agents(c *gophercloud.ServiceClient, id string) (result pagination.Pa return ListL3AgentsPage{pagination.SinglePageBase(r)} }) } + +// AddExternalGatewaysOptsBuilder allows extensions to add additional parameters +// to the AddExternalGateways request. +type AddExternalGatewaysOptsBuilder interface { + ToRouterAddExternalGatewaysMap() (map[string]any, error) +} + +// AddExternalGatewaysOpts represents the options for adding external gateways +// to a router. +type AddExternalGatewaysOpts struct { + ExternalGateways []GatewayInfo `json:"external_gateways" required:"true"` +} + +// ToRouterAddExternalGatewaysMap builds a request body from AddExternalGatewaysOpts. +func (opts AddExternalGatewaysOpts) ToRouterAddExternalGatewaysMap() (map[string]any, error) { + return gophercloud.BuildRequestBody(opts, "router") +} + +// AddExternalGateways adds external gateways to a router. +// This requires the external-gateway-multihoming extension. +func AddExternalGateways(ctx context.Context, c *gophercloud.ServiceClient, id string, opts AddExternalGatewaysOptsBuilder) (r UpdateResult) { + b, err := opts.ToRouterAddExternalGatewaysMap() + if err != nil { + r.Err = err + return + } + resp, err := c.Put(ctx, addExternalGatewaysURL(c, id), b, &r.Body, &gophercloud.RequestOpts{ + OkCodes: []int{200}, + }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + +// UpdateExternalGatewaysOptsBuilder allows extensions to add additional +// parameters to the UpdateExternalGateways request. +type UpdateExternalGatewaysOptsBuilder interface { + ToRouterUpdateExternalGatewaysMap() (map[string]any, error) +} + +// UpdateExternalGatewaysOpts represents the options for updating external +// gateways of a router. +type UpdateExternalGatewaysOpts struct { + ExternalGateways []GatewayInfo `json:"external_gateways" required:"true"` +} + +// ToRouterUpdateExternalGatewaysMap builds a request body from UpdateExternalGatewaysOpts. +func (opts UpdateExternalGatewaysOpts) ToRouterUpdateExternalGatewaysMap() (map[string]any, error) { + return gophercloud.BuildRequestBody(opts, "router") +} + +// UpdateExternalGateways updates external gateways of a router. +// This requires the external-gateway-multihoming extension. +func UpdateExternalGateways(ctx context.Context, c *gophercloud.ServiceClient, id string, opts UpdateExternalGatewaysOptsBuilder) (r UpdateResult) { + b, err := opts.ToRouterUpdateExternalGatewaysMap() + if err != nil { + r.Err = err + return + } + resp, err := c.Put(ctx, updateExternalGatewaysURL(c, id), b, &r.Body, &gophercloud.RequestOpts{ + OkCodes: []int{200}, + }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + +// RemoveExternalGatewaysOptsBuilder allows extensions to add additional +// parameters to the RemoveExternalGateways request. +type RemoveExternalGatewaysOptsBuilder interface { + ToRouterRemoveExternalGatewaysMap() (map[string]any, error) +} + +// RemoveExternalGatewaysOpts represents the options for removing external +// gateways from a router. +type RemoveExternalGatewaysOpts struct { + ExternalGateways []GatewayInfo `json:"external_gateways" required:"true"` +} + +// ToRouterRemoveExternalGatewaysMap builds a request body from RemoveExternalGatewaysOpts. +func (opts RemoveExternalGatewaysOpts) ToRouterRemoveExternalGatewaysMap() (map[string]any, error) { + return gophercloud.BuildRequestBody(opts, "router") +} + +// RemoveExternalGateways removes external gateways from a router. +// This requires the external-gateway-multihoming extension. +func RemoveExternalGateways(ctx context.Context, c *gophercloud.ServiceClient, id string, opts RemoveExternalGatewaysOptsBuilder) (r UpdateResult) { + b, err := opts.ToRouterRemoveExternalGatewaysMap() + if err != nil { + r.Err = err + return + } + resp, err := c.Put(ctx, removeExternalGatewaysURL(c, id), b, &r.Body, &gophercloud.RequestOpts{ + OkCodes: []int{200}, + }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} diff --git a/openstack/networking/v2/extensions/layer3/routers/testing/requests_test.go b/openstack/networking/v2/extensions/layer3/routers/testing/requests_test.go index f6cd2c0bbd..1125aa12c4 100644 --- a/openstack/networking/v2/extensions/layer3/routers/testing/requests_test.go +++ b/openstack/networking/v2/extensions/layer3/routers/testing/requests_test.go @@ -697,3 +697,203 @@ func TestListL3Agents(t *testing.T) { } th.CheckDeepEquals(t, expected, actual) } + +func TestAddExternalGateways(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + fakeServer.Mux.HandleFunc("/v2.0/routers/4e8e5957-649f-477b-9e5b-f1f75b21c03c/add_external_gateways", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "PUT") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestJSONRequest(t, r, ` +{ + "router": { + "external_gateways": [ + { + "network_id": "8ca37218-28ff-41cb-9b10-039601ea7e6b", + "external_fixed_ips": [ + {"subnet_id": "ab561bc4-1a8e-48f2-9fbd-376fcb1a1def"} + ] + } + ] + } +} + `) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, ` +{ + "router": { + "status": "ACTIVE", + "external_gateway_info": { + "network_id": "8ca37218-28ff-41cb-9b10-039601ea7e6b", + "external_fixed_ips": [ + {"ip_address": "192.0.2.17", "subnet_id": "ab561bc4-1a8e-48f2-9fbd-376fcb1a1def"} + ] + }, + "name": "router1", + "admin_state_up": true, + "tenant_id": "6b96ff0cb17a4b859e1e575d221683d3", + "distributed": false, + "id": "4e8e5957-649f-477b-9e5b-f1f75b21c03c" + } +} + `) + }) + + efi := []routers.ExternalFixedIP{ + {SubnetID: "ab561bc4-1a8e-48f2-9fbd-376fcb1a1def"}, + } + opts := routers.AddExternalGatewaysOpts{ + ExternalGateways: []routers.GatewayInfo{ + { + NetworkID: "8ca37218-28ff-41cb-9b10-039601ea7e6b", + ExternalFixedIPs: efi, + }, + }, + } + + n, err := routers.AddExternalGateways(context.TODO(), fake.ServiceClient(fakeServer), "4e8e5957-649f-477b-9e5b-f1f75b21c03c", opts).Extract() + th.AssertNoErr(t, err) + + th.AssertEquals(t, n.Name, "router1") + th.AssertEquals(t, n.ID, "4e8e5957-649f-477b-9e5b-f1f75b21c03c") + th.AssertEquals(t, n.GatewayInfo.NetworkID, "8ca37218-28ff-41cb-9b10-039601ea7e6b") +} + +func TestUpdateExternalGateways(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + fakeServer.Mux.HandleFunc("/v2.0/routers/4e8e5957-649f-477b-9e5b-f1f75b21c03c/update_external_gateways", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "PUT") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestJSONRequest(t, r, ` +{ + "router": { + "external_gateways": [ + { + "network_id": "8ca37218-28ff-41cb-9b10-039601ea7e6b", + "enable_snat": true, + "external_fixed_ips": [ + {"ip_address": "192.0.2.17", "subnet_id": "ab561bc4-1a8e-48f2-9fbd-376fcb1a1def"} + ] + } + ] + } +} + `) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, ` +{ + "router": { + "status": "ACTIVE", + "external_gateway_info": { + "network_id": "8ca37218-28ff-41cb-9b10-039601ea7e6b", + "enable_snat": true, + "external_fixed_ips": [ + {"ip_address": "192.0.2.17", "subnet_id": "ab561bc4-1a8e-48f2-9fbd-376fcb1a1def"} + ] + }, + "name": "router1", + "admin_state_up": true, + "tenant_id": "6b96ff0cb17a4b859e1e575d221683d3", + "distributed": false, + "id": "4e8e5957-649f-477b-9e5b-f1f75b21c03c" + } +} + `) + }) + + enableSNAT := true + efi := []routers.ExternalFixedIP{ + {IPAddress: "192.0.2.17", SubnetID: "ab561bc4-1a8e-48f2-9fbd-376fcb1a1def"}, + } + opts := routers.UpdateExternalGatewaysOpts{ + ExternalGateways: []routers.GatewayInfo{ + { + NetworkID: "8ca37218-28ff-41cb-9b10-039601ea7e6b", + EnableSNAT: &enableSNAT, + ExternalFixedIPs: efi, + }, + }, + } + + n, err := routers.UpdateExternalGateways(context.TODO(), fake.ServiceClient(fakeServer), "4e8e5957-649f-477b-9e5b-f1f75b21c03c", opts).Extract() + th.AssertNoErr(t, err) + + th.AssertEquals(t, n.Name, "router1") + th.AssertEquals(t, n.ID, "4e8e5957-649f-477b-9e5b-f1f75b21c03c") + th.AssertEquals(t, *n.GatewayInfo.EnableSNAT, true) +} + +func TestRemoveExternalGateways(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + fakeServer.Mux.HandleFunc("/v2.0/routers/4e8e5957-649f-477b-9e5b-f1f75b21c03c/remove_external_gateways", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "PUT") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestJSONRequest(t, r, ` +{ + "router": { + "external_gateways": [ + { + "network_id": "8ca37218-28ff-41cb-9b10-039601ea7e6b", + "external_fixed_ips": [ + {"ip_address": "192.0.2.17", "subnet_id": "ab561bc4-1a8e-48f2-9fbd-376fcb1a1def"} + ] + } + ] + } +} + `) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, ` +{ + "router": { + "status": "ACTIVE", + "external_gateway_info": null, + "name": "router1", + "admin_state_up": true, + "tenant_id": "6b96ff0cb17a4b859e1e575d221683d3", + "distributed": false, + "id": "4e8e5957-649f-477b-9e5b-f1f75b21c03c" + } +} + `) + }) + + efi := []routers.ExternalFixedIP{ + {IPAddress: "192.0.2.17", SubnetID: "ab561bc4-1a8e-48f2-9fbd-376fcb1a1def"}, + } + opts := routers.RemoveExternalGatewaysOpts{ + ExternalGateways: []routers.GatewayInfo{ + { + NetworkID: "8ca37218-28ff-41cb-9b10-039601ea7e6b", + ExternalFixedIPs: efi, + }, + }, + } + + n, err := routers.RemoveExternalGateways(context.TODO(), fake.ServiceClient(fakeServer), "4e8e5957-649f-477b-9e5b-f1f75b21c03c", opts).Extract() + th.AssertNoErr(t, err) + + th.AssertEquals(t, n.Name, "router1") + th.AssertEquals(t, n.ID, "4e8e5957-649f-477b-9e5b-f1f75b21c03c") + th.AssertEquals(t, n.GatewayInfo.NetworkID, "") +} diff --git a/openstack/networking/v2/extensions/layer3/routers/urls.go b/openstack/networking/v2/extensions/layer3/routers/urls.go index 87815aa6ec..b07c2fdc7b 100644 --- a/openstack/networking/v2/extensions/layer3/routers/urls.go +++ b/openstack/networking/v2/extensions/layer3/routers/urls.go @@ -23,3 +23,15 @@ func removeInterfaceURL(c *gophercloud.ServiceClient, id string) string { func listl3AgentsURL(c *gophercloud.ServiceClient, id string) string { return c.ServiceURL(resourcePath, id, "l3-agents") } + +func addExternalGatewaysURL(c *gophercloud.ServiceClient, id string) string { + return c.ServiceURL(resourcePath, id, "add_external_gateways") +} + +func updateExternalGatewaysURL(c *gophercloud.ServiceClient, id string) string { + return c.ServiceURL(resourcePath, id, "update_external_gateways") +} + +func removeExternalGatewaysURL(c *gophercloud.ServiceClient, id string) string { + return c.ServiceURL(resourcePath, id, "remove_external_gateways") +} From 94e6a57327ef32dbee0c76e868318ead19272c67 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Jan 2026 09:10:22 +0000 Subject: [PATCH 307/429] build(deps): bump golang.org/x/crypto from 0.46.0 to 0.47.0 Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.46.0 to 0.47.0. - [Commits](https://github.com/golang/crypto/compare/v0.46.0...v0.47.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-version: 0.47.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 91c175c962..c83558414b 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module github.com/gophercloud/gophercloud/v2 go 1.24.0 require ( - golang.org/x/crypto v0.46.0 + golang.org/x/crypto v0.47.0 gopkg.in/yaml.v2 v2.4.0 ) -require golang.org/x/sys v0.39.0 // indirect +require golang.org/x/sys v0.40.0 // indirect diff --git a/go.sum b/go.sum index 03a132e602..eacdf99c42 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ -golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= -golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= -golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= -golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= -golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= +golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= +golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= +golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= +golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= +golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= From 7e8c769e7044aafe3e09c7837c9895bfc98aa4be Mon Sep 17 00:00:00 2001 From: Stefan Majewsky Date: Fri, 16 Jan 2026 00:41:07 +0100 Subject: [PATCH 308/429] replace gopkg.in/yaml.v2 with go.yaml.in/yaml/v3 --- go.mod | 2 +- go.sum | 4 ++-- openstack/config/clouds/clouds.go | 2 +- openstack/container/v1/capsules/template.go | 2 +- openstack/orchestration/v1/stacks/environment.go | 2 +- openstack/orchestration/v1/stacks/template.go | 2 +- openstack/orchestration/v1/stacks/utils.go | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index c83558414b..e4dfa74850 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module github.com/gophercloud/gophercloud/v2 go 1.24.0 require ( + go.yaml.in/yaml/v3 v3.0.4 golang.org/x/crypto v0.47.0 - gopkg.in/yaml.v2 v2.4.0 ) require golang.org/x/sys v0.40.0 // indirect diff --git a/go.sum b/go.sum index eacdf99c42..aedfcaa0b6 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= @@ -6,5 +8,3 @@ golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/openstack/config/clouds/clouds.go b/openstack/config/clouds/clouds.go index eae6f38c8e..94c01645d9 100644 --- a/openstack/config/clouds/clouds.go +++ b/openstack/config/clouds/clouds.go @@ -28,7 +28,7 @@ import ( "reflect" "github.com/gophercloud/gophercloud/v2" - "gopkg.in/yaml.v2" + "go.yaml.in/yaml/v3" ) // Parse fetches a clouds.yaml file from disk and returns the parsed diff --git a/openstack/container/v1/capsules/template.go b/openstack/container/v1/capsules/template.go index b3b4446131..06df6ae938 100644 --- a/openstack/container/v1/capsules/template.go +++ b/openstack/container/v1/capsules/template.go @@ -3,7 +3,7 @@ package capsules import ( "encoding/json" - yaml "gopkg.in/yaml.v2" + yaml "go.yaml.in/yaml/v3" ) // Template is a structure that represents OpenStack Zun Capsule templates diff --git a/openstack/orchestration/v1/stacks/environment.go b/openstack/orchestration/v1/stacks/environment.go index bb9004a9f8..7efe29e5fd 100644 --- a/openstack/orchestration/v1/stacks/environment.go +++ b/openstack/orchestration/v1/stacks/environment.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" - yaml "gopkg.in/yaml.v2" + yaml "go.yaml.in/yaml/v3" ) // Environment is a structure that represents stack environments diff --git a/openstack/orchestration/v1/stacks/template.go b/openstack/orchestration/v1/stacks/template.go index af49c612a0..021267f56f 100644 --- a/openstack/orchestration/v1/stacks/template.go +++ b/openstack/orchestration/v1/stacks/template.go @@ -8,7 +8,7 @@ import ( "strings" "github.com/gophercloud/gophercloud/v2" - yaml "gopkg.in/yaml.v2" + yaml "go.yaml.in/yaml/v3" ) // Template is a structure that represents OpenStack Heat templates diff --git a/openstack/orchestration/v1/stacks/utils.go b/openstack/orchestration/v1/stacks/utils.go index 228335388f..36b2914a4f 100644 --- a/openstack/orchestration/v1/stacks/utils.go +++ b/openstack/orchestration/v1/stacks/utils.go @@ -9,7 +9,7 @@ import ( "reflect" "github.com/gophercloud/gophercloud/v2" - yaml "gopkg.in/yaml.v2" + yaml "go.yaml.in/yaml/v3" ) // Client is an interface that expects a Get method similar to http.Get. This From 7d61cd7d7c6c80939e61a27d3e72ac14c4c264bd Mon Sep 17 00:00:00 2001 From: Stefan Majewsky Date: Fri, 16 Jan 2026 15:34:54 +0100 Subject: [PATCH 309/429] orchestration: adjust template parsing logic for yaml/v3 - `map[any]any` is not unmarshaled anymore if all keys are strings, so type casting logic can be removed - version strings like `2014-10-16` are unmarshaled into `any` as `time.Time`, so for compatibility, this needs to be type-casted back into `string` manually --- .../v1/capsules/testing/fixtures_test.go | 12 +- .../orchestration/v1/stacks/environment.go | 121 ++++++++---------- openstack/orchestration/v1/stacks/template.go | 19 +-- openstack/orchestration/v1/stacks/utils.go | 38 +++--- .../orchestration/v1/stacks/utils_test.go | 15 --- 5 files changed, 73 insertions(+), 132 deletions(-) diff --git a/openstack/container/v1/capsules/testing/fixtures_test.go b/openstack/container/v1/capsules/testing/fixtures_test.go index e21b852569..00ef3404f6 100644 --- a/openstack/container/v1/capsules/testing/fixtures_test.go +++ b/openstack/container/v1/capsules/testing/fixtures_test.go @@ -144,9 +144,9 @@ var ValidYAMLTemplateParsed = map[string]any{ "app1": "web1", }, }, - "spec": map[any]any{ + "spec": map[string]any{ "restartPolicy": "Always", - "containers": []map[any]any{ + "containers": []map[string]any{ { "image": "ubuntu", "command": []any{ @@ -155,20 +155,20 @@ var ValidYAMLTemplateParsed = map[string]any{ "imagePullPolicy": "ifnotpresent", "workDir": "/root", "ports": []any{ - map[any]any{ + map[string]any{ "name": "nginx-port", "containerPort": 80, "hostPort": 80, "protocol": "TCP", }, }, - "resources": map[any]any{ - "requests": map[any]any{ + "resources": map[string]any{ + "requests": map[string]any{ "cpu": 1, "memory": 1024, }, }, - "env": map[any]any{ + "env": map[string]any{ "ENV1": "/usr/local/bin", "ENV2": "/usr/bin", }, diff --git a/openstack/orchestration/v1/stacks/environment.go b/openstack/orchestration/v1/stacks/environment.go index 7efe29e5fd..30fdcc00a6 100644 --- a/openstack/orchestration/v1/stacks/environment.go +++ b/openstack/orchestration/v1/stacks/environment.go @@ -46,87 +46,68 @@ func (e *Environment) getRRFileContents(ignoreIf igFunc) error { e.fileMaps = make(map[string]string) } - // get the resource registry - rr := e.Parsed["resource_registry"] + // get the resource registry, only process further if it is a map + rr, ok := e.Parsed["resource_registry"].(map[string]any) + if !ok { + return nil + } // search the resource registry for URLs - switch rr.(type) { - // process further only if the resource registry is a map - case map[string]any, map[any]any: - rrMap, err := toStringKeys(rr) - if err != nil { - return err - } - // the resource registry might contain a base URL for the resource. If - // such a field is present, use it. Otherwise, use the default base URL. - var baseURL string - if val, ok := rrMap["base_url"]; ok { - baseURL = val.(string) - } else { - baseURL = e.baseURL - } + // + // the resource registry might contain a base URL for the resource. If + // such a field is present, use it. Otherwise, use the default base URL. + var baseURL string + if val, ok := rr["base_url"]; ok { + baseURL = val.(string) + } else { + baseURL = e.baseURL + } - // The contents of the resource may be located in a remote file, which - // will be a template. Instantiate a temporary template to manage the - // contents. - tempTemplate := new(Template) - tempTemplate.baseURL = baseURL - tempTemplate.client = e.client + // The contents of the resource may be located in a remote file, which + // will be a template. Instantiate a temporary template to manage the + // contents. + tempTemplate := new(Template) + tempTemplate.baseURL = baseURL + tempTemplate.client = e.client - // Fetch the contents of remote resource URL's - if err = tempTemplate.getFileContents(rr, ignoreIf, false); err != nil { - return err - } - // check the `resources` section (if it exists) for more URL's. Note that - // the previous call to GetFileContents was (deliberately) not recursive - // as we want more control over where to look for URL's - if val, ok := rrMap["resources"]; ok { - switch val.(type) { - // process further only if the contents are a map - case map[string]any, map[any]any: - resourcesMap, err := toStringKeys(val) - if err != nil { - return err + // Fetch the contents of remote resource URL's + if err := tempTemplate.getFileContents(rr, ignoreIf, false); err != nil { + return err + } + // check the `resources` section (if it exists) for more URL's. Note that + // the previous call to GetFileContents was (deliberately) not recursive + // as we want more control over where to look for URL's + if resourcesMap, ok := rr["resources"].(map[string]any); ok { + for _, v := range resourcesMap { + if resourceMap, ok := v.(map[string]any); ok { + var resourceBaseURL string + // if base_url for the resource type is defined, use it + if val, ok := resourceMap["base_url"]; ok { + resourceBaseURL = val.(string) + } else { + resourceBaseURL = baseURL } - for _, v := range resourcesMap { - switch v.(type) { - case map[string]any, map[any]any: - resourceMap, err := toStringKeys(v) - if err != nil { - return err - } - var resourceBaseURL string - // if base_url for the resource type is defined, use it - if val, ok := resourceMap["base_url"]; ok { - resourceBaseURL = val.(string) - } else { - resourceBaseURL = baseURL - } - tempTemplate.baseURL = resourceBaseURL - if err := tempTemplate.getFileContents(v, ignoreIf, false); err != nil { - return err - } - } + tempTemplate.baseURL = resourceBaseURL + if err := tempTemplate.getFileContents(v, ignoreIf, false); err != nil { + return err } } } - // if the resource registry contained any URL's, store them. This can - // then be passed as parameter to api calls to Heat api. - e.Files = tempTemplate.Files + } + // if the resource registry contained any URL's, store them. This can + // then be passed as parameter to api calls to Heat api. + e.Files = tempTemplate.Files - // In case some element was updated, regenerate the string representation - if len(e.Files) > 0 { - var err error - e.Bin, err = yaml.Marshal(&e.Parsed) - if err != nil { - return fmt.Errorf("failed to marshal updated environment: %w", err) - } + // In case some element was updated, regenerate the string representation + if len(e.Files) > 0 { + var err error + e.Bin, err = yaml.Marshal(&e.Parsed) + if err != nil { + return fmt.Errorf("failed to marshal updated environment: %w", err) } - - return nil - default: - return nil } + + return nil } // function to choose keys whose values are other environment files diff --git a/openstack/orchestration/v1/stacks/template.go b/openstack/orchestration/v1/stacks/template.go index 021267f56f..0943aae978 100644 --- a/openstack/orchestration/v1/stacks/template.go +++ b/openstack/orchestration/v1/stacks/template.go @@ -84,12 +84,7 @@ func (t *Template) makeChildTemplate(childURL string, ignoreIf igFunc, recurse b // Applies the transformation for getFileContents() to just one element of a map. // In case the element requires transforming, the function returns its new value. -func (t *Template) mapElemFileContents(k any, v any, ignoreIf igFunc, recurse bool) (any, error) { - key, ok := k.(string) - if !ok { - return nil, fmt.Errorf("can't convert map key to string: %v", k) - } - +func (t *Template) mapElemFileContents(key string, v any, ignoreIf igFunc, recurse bool) (any, error) { value, ok := v.(string) if !ok { // if the value is not a string, recursively parse that value @@ -153,18 +148,6 @@ func (t *Template) getFileContents(te any, ignoreIf igFunc, recurse bool) error updated = true } } - // same if te is a map[non-string] (can't group with above case because we - // can't range over and update 'te' without knowing its key type) - case map[any]any: - for k, v := range teTyped { - newVal, err := t.mapElemFileContents(k, v, ignoreIf, recurse) - if err != nil { - return err - } else if newVal != nil { - teTyped[k] = newVal - updated = true - } - } // if te is a slice, call the function on each element of the slice. case []any: for i := range teTyped { diff --git a/openstack/orchestration/v1/stacks/utils.go b/openstack/orchestration/v1/stacks/utils.go index 36b2914a4f..bb936ae1b3 100644 --- a/openstack/orchestration/v1/stacks/utils.go +++ b/openstack/orchestration/v1/stacks/utils.go @@ -6,7 +6,7 @@ import ( "io" "net/http" "path/filepath" - "reflect" + "time" "github.com/gophercloud/gophercloud/v2" yaml "go.yaml.in/yaml/v3" @@ -113,10 +113,20 @@ func (t *TE) Parse() error { if err := t.Fetch(); err != nil { return err } - if jerr := json.Unmarshal(t.Bin, &t.Parsed); jerr != nil { - if yerr := yaml.Unmarshal(t.Bin, &t.Parsed); yerr != nil { - return ErrInvalidDataFormat{} - } + + // either parse as JSON... + if jerr := json.Unmarshal(t.Bin, &t.Parsed); jerr == nil { + return nil + } + + // ... or as YAML (but in this case, take extra care because yaml.Unmarshal() + // might incorrectly decode the `heat_template_version` attribute as a + // time.Time instead of as a string because it looks like "YYYY-MM-DD") + if yerr := yaml.Unmarshal(t.Bin, &t.Parsed); yerr != nil { + return ErrInvalidDataFormat{} + } + if versionAsTime, ok := t.Parsed["heat_template_version"].(time.Time); ok { + t.Parsed["heat_template_version"] = versionAsTime.Format(time.DateOnly) } return nil } @@ -124,21 +134,3 @@ func (t *TE) Parse() error { // igfunc is a parameter used by GetFileContents and GetRRFileContents to check // for valid URL's. type igFunc func(string, any) bool - -// convert map[any]any to map[string]any -func toStringKeys(m any) (map[string]any, error) { - switch m.(type) { - case map[string]any, map[any]any: - typedMap := make(map[string]any) - if _, ok := m.(map[any]any); ok { - for k, v := range m.(map[any]any) { - typedMap[k.(string)] = v - } - } else { - typedMap = m.(map[string]any) - } - return typedMap, nil - default: - return nil, gophercloud.ErrUnexpectedType{Expected: "map[string]any/map[any]any", Actual: fmt.Sprintf("%v", reflect.TypeOf(m))} - } -} diff --git a/openstack/orchestration/v1/stacks/utils_test.go b/openstack/orchestration/v1/stacks/utils_test.go index bb90993702..1daceefa93 100644 --- a/openstack/orchestration/v1/stacks/utils_test.go +++ b/openstack/orchestration/v1/stacks/utils_test.go @@ -10,21 +10,6 @@ import ( th "github.com/gophercloud/gophercloud/v2/testhelper" ) -func TestToStringKeys(t *testing.T) { - var test1 any = map[any]any{ - "Adam": "Smith", - "Isaac": "Newton", - } - result1, err := toStringKeys(test1) - th.AssertNoErr(t, err) - - expected := map[string]any{ - "Adam": "Smith", - "Isaac": "Newton", - } - th.AssertDeepEquals(t, result1, expected) -} - func TestGetBasePath(t *testing.T) { _, err := getBasePath() th.AssertNoErr(t, err) From ecbd02fc6f5abc0095284e693f3e6c27c2d81541 Mon Sep 17 00:00:00 2001 From: Mohammed Al-Dokimi Date: Sun, 18 Jan 2026 01:06:53 +0000 Subject: [PATCH 310/429] networking/v2/layer3/routers: Fix acceptance tests and linting --- .../v2/extensions/layer3/routers_test.go | 30 ++++++++++++++++--- .../v2/extensions/layer3/routers/doc.go | 12 ++------ 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/internal/acceptance/openstack/networking/v2/extensions/layer3/routers_test.go b/internal/acceptance/openstack/networking/v2/extensions/layer3/routers_test.go index be275f2ce1..9aefcb6630 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/layer3/routers_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/layer3/routers_test.go @@ -327,14 +327,25 @@ func TestLayer3RouterExternalGateways(t *testing.T) { tools.PrintResource(t, updatedRouter) // Test UpdateExternalGateways + // Note: UpdateExternalGateways requires external_fixed_ips to identify which gateway to update t.Logf("Attempting to update external gateways of router %s", router.ID) - enableSNAT := true + // Get current external_fixed_ips from the router to identify the gateway + currentFixedIPs := make([]routers.ExternalFixedIP, len(updatedRouter.GatewayInfo.ExternalFixedIPs)) + for i, ip := range updatedRouter.GatewayInfo.ExternalFixedIPs { + currentFixedIPs[i] = routers.ExternalFixedIP{ + IPAddress: ip.IPAddress, + SubnetID: ip.SubnetID, + } + } + + enableSNAT := false updateOpts := routers.UpdateExternalGatewaysOpts{ ExternalGateways: []routers.GatewayInfo{ { - NetworkID: choices.ExternalNetworkID, - EnableSNAT: &enableSNAT, + NetworkID: updatedRouter.GatewayInfo.NetworkID, + EnableSNAT: &enableSNAT, + ExternalFixedIPs: currentFixedIPs, }, }, } @@ -351,12 +362,23 @@ func TestLayer3RouterExternalGateways(t *testing.T) { tools.PrintResource(t, updatedRouter) // Test RemoveExternalGateways + // Note: RemoveExternalGateways requires external_fixed_ips to identify which gateway to remove t.Logf("Attempting to remove external gateways from router %s", router.ID) + // Get current external_fixed_ips from the updated router + currentFixedIPs = make([]routers.ExternalFixedIP, len(updatedRouter.GatewayInfo.ExternalFixedIPs)) + for i, ip := range updatedRouter.GatewayInfo.ExternalFixedIPs { + currentFixedIPs[i] = routers.ExternalFixedIP{ + IPAddress: ip.IPAddress, + SubnetID: ip.SubnetID, + } + } + removeOpts := routers.RemoveExternalGatewaysOpts{ ExternalGateways: []routers.GatewayInfo{ { - NetworkID: choices.ExternalNetworkID, + NetworkID: updatedRouter.GatewayInfo.NetworkID, + ExternalFixedIPs: currentFixedIPs, }, }, } diff --git a/openstack/networking/v2/extensions/layer3/routers/doc.go b/openstack/networking/v2/extensions/layer3/routers/doc.go index 4faa862fc1..772c9e3bbf 100644 --- a/openstack/networking/v2/extensions/layer3/routers/doc.go +++ b/openstack/networking/v2/extensions/layer3/routers/doc.go @@ -136,9 +136,7 @@ Example to List an L3 agents for a Router fmt.Printf("%+v\n", agent) } -Example to Add External Gateways to a Router - -This requires the external-gateway-multihoming extension. +Example to Add External Gateways to a Router: This requires the external-gateway-multihoming extension. routerID := "4e8e5957-649f-477b-9e5b-f1f75b21c03c" @@ -158,9 +156,7 @@ This requires the external-gateway-multihoming extension. panic(err) } -Example to Update External Gateways of a Router - -This requires the external-gateway-multihoming extension. +Example to Update External Gateways of a Router: This requires the external-gateway-multihoming extension. routerID := "4e8e5957-649f-477b-9e5b-f1f75b21c03c" @@ -182,9 +178,7 @@ This requires the external-gateway-multihoming extension. panic(err) } -Example to Remove External Gateways from a Router - -This requires the external-gateway-multihoming extension. +Example to Remove External Gateways from a Router: This requires the external-gateway-multihoming extension. routerID := "4e8e5957-649f-477b-9e5b-f1f75b21c03c" From 9753503b19ba49bb0cc48e1add1b2a11422ebb1f Mon Sep 17 00:00:00 2001 From: Daniel Lawton Date: Thu, 22 Jan 2026 10:59:27 +0000 Subject: [PATCH 311/429] Networking V2: Added support for ML2 extension port_trusted_vif field. This allows users to create and update the 'trusted' status of a port via the ML2 extension. Includes: - Extension package definition - Request/Response structs (CreateOptsExt, UpdateOptsExt) - Unit tests and acceptance tests Signed-off-by: Daniel Lawton --- .github/workflows/functional-networking.yaml | 2 +- .../openstack/networking/v2/ports_test.go | 54 ++++ .../v2/extensions/portstrustedvif/doc.go | 74 ++++++ .../v2/extensions/portstrustedvif/requests.go | 53 ++++ .../v2/extensions/portstrustedvif/results.go | 6 + .../portstrustedvif/testing/fixtures_test.go | 161 ++++++++++++ .../portstrustedvif/testing/requests_test.go | 242 ++++++++++++++++++ 7 files changed, 591 insertions(+), 1 deletion(-) create mode 100644 openstack/networking/v2/extensions/portstrustedvif/doc.go create mode 100644 openstack/networking/v2/extensions/portstrustedvif/requests.go create mode 100644 openstack/networking/v2/extensions/portstrustedvif/results.go create mode 100644 openstack/networking/v2/extensions/portstrustedvif/testing/fixtures_test.go create mode 100644 openstack/networking/v2/extensions/portstrustedvif/testing/requests_test.go diff --git a/.github/workflows/functional-networking.yaml b/.github/workflows/functional-networking.yaml index 8ab9d9798a..e7bf14d7ee 100644 --- a/.github/workflows/functional-networking.yaml +++ b/.github/workflows/functional-networking.yaml @@ -65,7 +65,7 @@ jobs: enable_plugin neutron-dynamic-routing https://github.com/openstack/neutron-dynamic-routing ${{ matrix.openstack_version }} enable_plugin neutron-vpnaas https://github.com/openstack/neutron-vpnaas ${{ matrix.openstack_version }} enable_plugin networking-bgpvpn https://github.com/openstack/networking-bgpvpn.git ${{ matrix.openstack_version }} - Q_ML2_PLUGIN_EXT_DRIVERS=qos,port_security,dns_domain_keywords + Q_ML2_PLUGIN_EXT_DRIVERS=qos,port_security,dns_domain_keywords,port_trusted BGP_SCHEDULER_DRIVER=neutron_dynamic_routing.services.bgp.scheduler.bgp_dragent_scheduler.StaticScheduler [[post-config|\$NEUTRON_CONF]] diff --git a/internal/acceptance/openstack/networking/v2/ports_test.go b/internal/acceptance/openstack/networking/v2/ports_test.go index f6ff48e829..1506e4f8d6 100644 --- a/internal/acceptance/openstack/networking/v2/ports_test.go +++ b/internal/acceptance/openstack/networking/v2/ports_test.go @@ -13,6 +13,7 @@ import ( "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/extradhcpopts" "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/portsecurity" + "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/portstrustedvif" "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/ports" th "github.com/gophercloud/gophercloud/v2/testhelper" ) @@ -467,6 +468,59 @@ func TestPortsWithExtraDHCPOptsCRUD(t *testing.T) { tools.PrintResource(t, newPort) } +func TestPortsTrustedVIFCRUD(t *testing.T) { + client, err := clients.NewNetworkV2Client() + if err != nil { + t.Fatalf("Unable to create a network client: %v", err) + } + + // Create Network + network, err := CreateNetwork(t, client) + if err != nil { + t.Fatalf("Unable to create network: %v", err) + } + defer DeleteNetwork(t, client, network.ID) + + // Create Subnet + subnet, err := CreateSubnet(t, client, network.ID) + if err != nil { + t.Fatalf("Unable to create subnet: %v", err) + } + defer DeleteSubnet(t, client, subnet.ID) + + // Create port + port, err := CreatePort(t, client, network.ID, subnet.ID) + if err != nil { + t.Fatalf("Unable to create port: %v", err) + } + defer DeletePort(t, client, port.ID) + + var portWithExt struct { + ports.Port + portstrustedvif.PortTrustedVIFExt + } + + err = ports.Get(context.TODO(), client, port.ID).ExtractInto(&portWithExt) + if err != nil { + t.Fatalf("Unable to create port: %v", err) + } + + tools.PrintResource(t, portWithExt) + + // Update Port Trusted VIF status as true + iTrue := true + portUpdateOpts := ports.UpdateOpts{} + updateOpts := portstrustedvif.PortUpdateOptsExt{ + UpdateOptsBuilder: portUpdateOpts, + PortTrustedVIF: &iTrue, + } + + err = ports.Update(context.TODO(), client, port.ID, updateOpts).ExtractInto(&portWithExt) + if err != nil { + t.Fatalf("Unable to update port: %v", err) + } +} + func TestPortsRevision(t *testing.T) { client, err := clients.NewNetworkV2Client() th.AssertNoErr(t, err) diff --git a/openstack/networking/v2/extensions/portstrustedvif/doc.go b/openstack/networking/v2/extensions/portstrustedvif/doc.go new file mode 100644 index 0000000000..9efedf04ad --- /dev/null +++ b/openstack/networking/v2/extensions/portstrustedvif/doc.go @@ -0,0 +1,74 @@ +/* +Package portstrustedvif provides information and interaction with the port +trusted vif extension which adds trusted attributes to the port resource +for the OpenStack Networking service. + +Example to Get a Port with a Port Trusted VIF + + var portWithPortTrustedVIFExtension struct { + ports.Port + portstrustedvif.PortTrustedVIFExt + } + + portID := "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2" + + err := ports.Get(context.TODO(), networkingClient, portID).ExtractInto(&portWithPortTrustedVIFExtension) + if err != nil { + panic(err) + } + + fmt.Printf("%+v\n", portWithPortTrustedVIFExtension) + +Example to Create a Port With Port Trusted VIF set as true + + var portWithPortTrustedVIFExtension struct { + ports.Port + portstrustedvif.PortTrustedVIFExt + } + + iTrue := true + networkID := "4e8e5957-649f-477b-9e5b-f1f75b21c03c" + subnetID := "a87cc70a-3e15-4acf-8205-9b711a3531b7" + + portCreateOpts := ports.CreateOpts{ + NetworkID: networkID, + FixedIPs: []ports.IP{ports.IP{SubnetID: subnetID}}, + } + + createOpts := portstrustedvif.PortCreateOptsExt{ + CreateOptsBuilder: portCreateOpts, + PortTrustedVIF: &iTrue, + } + + err := ports.Create(context.TODO(), networkingClient, createOpts).ExtractInto(&portWithPortTrustedVIFExtension) + if err != nil { + panic(err) + } + + fmt.Printf("%+v\n", portWithPortTrustedVIFExtension) + +Example to Update the status of the Port Trusted VIF to false on an Existing Port + + var portWithPortTrustedVIDExtension struct { + ports.Port + portstrustedvif.PortTrustedVIFExt + } + + iFalse := false + portID := "65c0ee9f-d634-4522-8954-51021b570b0d" + + portUpdateOpts := ports.UpdateOpts{} + updateOpts := portstrustedvif.PortUpdateOptsExt{ + UpdateOptsBuilder: portUpdateOpts, + PortTrustedVIF: &iFalse, + } + + err := ports.Update(context.TODO(), networkingClient, portID, updateOpts).ExtractInto(&portWithPortTrustedVIFExtension) + if err != nil { + panic(err) + } + + fmt.Printf("%+v\n", portWithPortTrustedVIFExtension) +*/ + +package portstrustedvif diff --git a/openstack/networking/v2/extensions/portstrustedvif/requests.go b/openstack/networking/v2/extensions/portstrustedvif/requests.go new file mode 100644 index 0000000000..c4166ce1bd --- /dev/null +++ b/openstack/networking/v2/extensions/portstrustedvif/requests.go @@ -0,0 +1,53 @@ +package portstrustedvif + +import ( + "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/ports" +) + +// PortCreateOptsExt adds port trusted VIF options to the base ports.CreateOpts. +type PortCreateOptsExt struct { + ports.CreateOptsBuilder + + // PortTrustedVIF toggles the port's trusted VIF status. + PortTrustedVIF *bool `json:"trusted,omitempty"` +} + +// To PortCreateMap casts a CreateOpts struct to a map +func (opts PortCreateOptsExt) ToPortCreateMap() (map[string]any, error) { + base, err := opts.CreateOptsBuilder.ToPortCreateMap() + if err != nil { + return nil, err + } + + port := base["port"].(map[string]any) + + if opts.PortTrustedVIF != nil { + port["trusted"] = *opts.PortTrustedVIF + } + + return base, nil +} + +// PortUpdateOptsExt adds port trusted VIF options to the base ports.UpdateOpts. +type PortUpdateOptsExt struct { + ports.UpdateOptsBuilder + + // PortTrustedVIF updates the port's trusted VIF status. + PortTrustedVIF *bool `json:"trusted,omitempty"` +} + +// ToPortUpdateMap casts a UpdateOpts struct to a map. +func (opts PortUpdateOptsExt) ToPortUpdateMap() (map[string]any, error) { + base, err := opts.UpdateOptsBuilder.ToPortUpdateMap() + if err != nil { + return nil, err + } + + port := base["port"].(map[string]any) + + if opts.PortTrustedVIF != nil { + port["trusted"] = *opts.PortTrustedVIF + } + + return base, nil +} diff --git a/openstack/networking/v2/extensions/portstrustedvif/results.go b/openstack/networking/v2/extensions/portstrustedvif/results.go new file mode 100644 index 0000000000..39cfeacfaa --- /dev/null +++ b/openstack/networking/v2/extensions/portstrustedvif/results.go @@ -0,0 +1,6 @@ +package portstrustedvif + +type PortTrustedVIFExt struct { + // PortTrustedVIF stores information about whether a SR-IOV port should be trusted + PortTrustedVIF *bool `json:"trusted"` +} diff --git a/openstack/networking/v2/extensions/portstrustedvif/testing/fixtures_test.go b/openstack/networking/v2/extensions/portstrustedvif/testing/fixtures_test.go new file mode 100644 index 0000000000..0a9df88bbe --- /dev/null +++ b/openstack/networking/v2/extensions/portstrustedvif/testing/fixtures_test.go @@ -0,0 +1,161 @@ +package testing + +const ListResponse = ` +{ + "ports": [ + { + "status": "ACTIVE", + "binding:host_id": "devstack", + "name": "", + "admin_state_up": true, + "network_id": "70c1db1f-b701-45bd-96e0-a313ee3430b3", + "tenant_id": "", + "device_owner": "network:router_gateway", + "mac_address": "fa:16:3e:58:42:ed", + "binding:vnic_type": "normal", + "fixed_ips": [ + { + "subnet_id": "008ba151-0b8c-4a67-98b5-0d2b87666062", + "ip_address": "172.24.4.2" + } + ], + "id": "d80b1a3b-4fc1-49f3-952e-1e2ab7081d8b", + "security_groups": [], + "dns_name": "test-port", + "dns_assignment": [ + { + "hostname": "test-port", + "ip_address": "172.24.4.2", + "fqdn": "test-port.openstack.local." + } + ], + "device_id": "9ae135f4-b6e0-4dad-9e91-3c223e385824", + "port_security_enabled": false, + "trusted": true, + "created_at": "2019-06-30T04:15:37", + "updated_at": "2019-06-30T05:18:49" + } + ] +} +` + +const GetPortTrustedVIFStatusResponse = ` +{ + "port": { + "status": "DOWN", + "name": "private-port", + "admin_state_up": true, + "network_id": "a87cc70a-3e15-4acf-8205-9b711a3531b7", + "tenant_id": "d6700c0c9ffa4f1cb322cd4a1f3906fa", + "device_owner": "", + "mac_address": "fa:16:3e:c9:cb:f0", + "fixed_ips": [ + { + "subnet_id": "a0304c3a-4f08-4c43-88af-d796509c97d2", + "ip_address": "10.0.0.1" + } + ], + "id": "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2", + "trusted": false, + "device_id": "" + } +} +` +const GetPortTrustedVIFUnsetResponse = ` +{ + "port": { + "status": "DOWN", + "name": "private-port", + "admin_state_up": true, + "network_id": "a87cc70a-3e15-4acf-8205-9b711a3531b7", + "tenant_id": "d6700c0c9ffa4f1cb322cd4a1f3906fa", + "device_owner": "", + "mac_address": "fa:16:3e:c9:cb:f0", + "fixed_ips": [ + { + "subnet_id": "a0304c3a-4f08-4c43-88af-d796509c97d2", + "ip_address": "10.0.0.1" + } + ], + "id": "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2", + "device_id": "" + } +} +` + +const CreatePortTrustedVIFRequest = ` +{ + "port": { + "network_id": "a87cc70a-3e15-4acf-8205-9b711a3531b7", + "name": "private-port", + "admin_state_up": true, + "fixed_ips": [ + { + "subnet_id": "a0304c3a-4f08-4c43-88af-d796509c97d2", + "ip_address": "10.0.0.2" + } + ], + "trusted": true + } +}` + +const CreatePortTrustedVIFResponse = ` +{ + "port": { + "status": "DOWN", + "name": "private-port", + "admin_state_up": true, + "network_id": "a87cc70a-3e15-4acf-8205-9b711a3531b7", + "tenant_id": "d6700c0c9ffa4f1cb322cd4a1f3906fa", + "device_owner": "", + "mac_address": "fa:16:3e:c9:cb:f0", + "fixed_ips": [ + { + "subnet_id": "a0304c3a-4f08-4c43-88af-d796509c97d2", + "ip_address": "10.0.0.2" + } + ], + "id": "65c0ee9f-d634-4522-8954-51021b570b0d", + "trusted": true, + "device_id": "" + } +}` + +const UpdatePortTrustedVIFRequest = ` +{ + "port": { + "trusted": false + } +}` + +const UpdatePortTrustedVIFResponse = ` +{ + "port": { + "status": "DOWN", + "name": "private-port", + "admin_state_up": true, + "network_id": "a87cc70a-3e15-4acf-8205-9b711a3531b7", + "tenant_id": "d6700c0c9ffa4f1cb322cd4a1f3906fa", + "device_owner": "", + "mac_address": "fa:16:3e:c9:cb:f0", + "fixed_ips": [ + { + "subnet_id": "a0304c3a-4f08-4c43-88af-d796509c97d2", + "ip_address": "10.0.0.3" + } + ], + "allowed_address_pairs": [ + { + "ip_address": "10.0.0.4", + "mac_address": "fa:16:3e:c9:cb:f0" + } + ], + "id": "65c0ee9f-d634-4522-8954-51021b570b0d", + "security_groups": [ + "f0ac4394-7e4a-4409-9701-ba8be283dbc3" + ], + "trusted": false, + "device_id": "" + } +} +` diff --git a/openstack/networking/v2/extensions/portstrustedvif/testing/requests_test.go b/openstack/networking/v2/extensions/portstrustedvif/testing/requests_test.go new file mode 100644 index 0000000000..e768dda87b --- /dev/null +++ b/openstack/networking/v2/extensions/portstrustedvif/testing/requests_test.go @@ -0,0 +1,242 @@ +package testing + +import ( + "context" + "fmt" + "net/http" + "testing" + "time" + + fake "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/common" + "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/portstrustedvif" + "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/ports" + th "github.com/gophercloud/gophercloud/v2/testhelper" +) + +func TestList(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + fakeServer.Mux.HandleFunc("/v2.0/ports", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, ListResponse) + }) + + type PortWithExt struct { + ports.Port + portstrustedvif.PortTrustedVIFExt + } + var actual []PortWithExt + + iTrue := true + expected := []PortWithExt{ + { + Port: ports.Port{ + Status: "ACTIVE", + Name: "", + AdminStateUp: true, + NetworkID: "70c1db1f-b701-45bd-96e0-a313ee3430b3", + TenantID: "", + DeviceOwner: "network:router_gateway", + MACAddress: "fa:16:3e:58:42:ed", + FixedIPs: []ports.IP{ + { + SubnetID: "008ba151-0b8c-4a67-98b5-0d2b87666062", + IPAddress: "172.24.4.2", + }, + }, + ID: "d80b1a3b-4fc1-49f3-952e-1e2ab7081d8b", + SecurityGroups: []string{}, + DeviceID: "9ae135f4-b6e0-4dad-9e91-3c223e385824", + CreatedAt: time.Date(2019, time.June, 30, 4, 15, 37, 0, time.UTC), + UpdatedAt: time.Date(2019, time.June, 30, 5, 18, 49, 0, time.UTC), + }, + PortTrustedVIFExt: portstrustedvif.PortTrustedVIFExt{ + PortTrustedVIF: &iTrue, + }, + }, + } + + allPages, err := ports.List(fake.ServiceClient(fakeServer), ports.ListOpts{}).AllPages(context.TODO()) + th.AssertNoErr(t, err) + + err = ports.ExtractPortsInto(allPages, &actual) + th.AssertNoErr(t, err) + + th.CheckDeepEquals(t, expected, actual) +} + +func TestGet(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + fakeServer.Mux.HandleFunc("/v2.0/ports/46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, GetPortTrustedVIFStatusResponse) + }) + + var s struct { + ports.Port + portstrustedvif.PortTrustedVIFExt + } + + err := ports.Get(context.TODO(), fake.ServiceClient(fakeServer), "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2").ExtractInto(&s) + th.AssertNoErr(t, err) + + th.AssertEquals(t, s.Status, "DOWN") + th.AssertEquals(t, s.Name, "private-port") + th.AssertEquals(t, s.AdminStateUp, true) + th.AssertEquals(t, s.NetworkID, "a87cc70a-3e15-4acf-8205-9b711a3531b7") + th.AssertEquals(t, s.TenantID, "d6700c0c9ffa4f1cb322cd4a1f3906fa") + th.AssertEquals(t, s.DeviceOwner, "") + th.AssertEquals(t, s.MACAddress, "fa:16:3e:c9:cb:f0") + th.AssertDeepEquals(t, s.FixedIPs, []ports.IP{ + {SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.1"}, + }) + th.AssertEquals(t, s.ID, "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2") + th.AssertEquals(t, s.DeviceID, "") + + if s.PortTrustedVIF == nil { + t.Fatalf("Expected s.PortTrustedVIF to be not nil") + } + th.AssertEquals(t, *s.PortTrustedVIF, false) +} + +func TestGetUnset(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + fakeServer.Mux.HandleFunc("/v2.0/ports/46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, GetPortTrustedVIFUnsetResponse) + }) + + var s struct { + ports.Port + portstrustedvif.PortTrustedVIFExt + } + + err := ports.Get(context.TODO(), fake.ServiceClient(fakeServer), "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2").ExtractInto(&s) + th.AssertNoErr(t, err) + + th.AssertEquals(t, s.Status, "DOWN") + th.AssertEquals(t, s.Name, "private-port") + th.AssertEquals(t, s.AdminStateUp, true) + th.AssertEquals(t, s.NetworkID, "a87cc70a-3e15-4acf-8205-9b711a3531b7") + th.AssertEquals(t, s.TenantID, "d6700c0c9ffa4f1cb322cd4a1f3906fa") + th.AssertEquals(t, s.DeviceOwner, "") + th.AssertEquals(t, s.MACAddress, "fa:16:3e:c9:cb:f0") + th.AssertDeepEquals(t, s.FixedIPs, []ports.IP{ + {SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.1"}, + }) + th.AssertEquals(t, s.ID, "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2") + th.AssertEquals(t, s.DeviceID, "") + + if s.PortTrustedVIF != nil { + t.Fatalf("Expected s.PortTrustedVIF to be nil") + } +} + +func TestCreateWithPortTrustedVIF(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + fakeServer.Mux.HandleFunc("/v2.0/ports", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestJSONRequest(t, r, CreatePortTrustedVIFRequest) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + + fmt.Fprint(w, CreatePortTrustedVIFResponse) + }) + + var portWithExt struct { + ports.Port + portstrustedvif.PortTrustedVIFExt + } + + asu := true + portTrustedVIFStatus := true + options := ports.CreateOpts{ + Name: "private-port", + AdminStateUp: &asu, + NetworkID: "a87cc70a-3e15-4acf-8205-9b711a3531b7", + FixedIPs: []ports.IP{ + {SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.2"}, + }, + } + createOpts := portstrustedvif.PortCreateOptsExt{ + CreateOptsBuilder: options, + PortTrustedVIF: &portTrustedVIFStatus, + } + err := ports.Create(context.TODO(), fake.ServiceClient(fakeServer), createOpts).ExtractInto(&portWithExt) + th.AssertNoErr(t, err) + + th.AssertEquals(t, portWithExt.Status, "DOWN") + th.AssertEquals(t, portWithExt.Name, "private-port") + th.AssertEquals(t, portWithExt.AdminStateUp, true) + th.AssertEquals(t, portWithExt.NetworkID, "a87cc70a-3e15-4acf-8205-9b711a3531b7") + th.AssertEquals(t, portWithExt.TenantID, "d6700c0c9ffa4f1cb322cd4a1f3906fa") + th.AssertEquals(t, portWithExt.DeviceOwner, "") + th.AssertEquals(t, portWithExt.MACAddress, "fa:16:3e:c9:cb:f0") + th.AssertDeepEquals(t, portWithExt.FixedIPs, []ports.IP{ + {SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.2"}, + }) + th.AssertEquals(t, portWithExt.ID, "65c0ee9f-d634-4522-8954-51021b570b0d") + th.AssertEquals(t, *portWithExt.PortTrustedVIF, true) +} + +func TestUpdatePortTrustedVIF(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + fakeServer.Mux.HandleFunc("/v2.0/ports/65c0ee9f-d634-4522-8954-51021b570b0d", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "PUT") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestJSONRequest(t, r, UpdatePortTrustedVIFRequest) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, UpdatePortTrustedVIFResponse) + }) + + var portWithExt struct { + ports.Port + portstrustedvif.PortTrustedVIFExt + } + + portTrustedVIFStatus := false + portUpdateOpts := ports.UpdateOpts{} + updateOpts := portstrustedvif.PortUpdateOptsExt{ + UpdateOptsBuilder: portUpdateOpts, + PortTrustedVIF: &portTrustedVIFStatus, + } + + err := ports.Update(context.TODO(), fake.ServiceClient(fakeServer), "65c0ee9f-d634-4522-8954-51021b570b0d", updateOpts).ExtractInto(&portWithExt) + th.AssertNoErr(t, err) + + th.AssertEquals(t, portWithExt.Name, "private-port") + th.AssertDeepEquals(t, *portWithExt.PortTrustedVIF, false) +} From cab952c98de413faea477c945f774fca75cf9308 Mon Sep 17 00:00:00 2001 From: Mohammed Al-Dokimi Date: Thu, 22 Jan 2026 19:19:54 +0000 Subject: [PATCH 312/429] networking/v2/layer3/routers: Remove 404 failuer skipping --- .../v2/extensions/layer3/routers_test.go | 24 +++---------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/internal/acceptance/openstack/networking/v2/extensions/layer3/routers_test.go b/internal/acceptance/openstack/networking/v2/extensions/layer3/routers_test.go index 9aefcb6630..e6519472c6 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/layer3/routers_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/layer3/routers_test.go @@ -4,11 +4,9 @@ package layer3 import ( "context" - "net/http" "strings" "testing" - "github.com/gophercloud/gophercloud/v2" "github.com/gophercloud/gophercloud/v2/internal/acceptance/clients" networking "github.com/gophercloud/gophercloud/v2/internal/acceptance/openstack/networking/v2" "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" @@ -315,13 +313,7 @@ func TestLayer3RouterExternalGateways(t *testing.T) { } updatedRouter, err := routers.AddExternalGateways(context.TODO(), client, router.ID, addOpts).Extract() - if err != nil { - // If we get a 404, the extension might not be fully functional - if gophercloud.ResponseCodeIs(err, http.StatusNotFound) { - t.Skipf("AddExternalGateways not supported: %v", err) - } - th.AssertNoErr(t, err) - } + th.AssertNoErr(t, err) t.Logf("Successfully added external gateways to router %s", router.ID) tools.PrintResource(t, updatedRouter) @@ -351,12 +343,7 @@ func TestLayer3RouterExternalGateways(t *testing.T) { } updatedRouter, err = routers.UpdateExternalGateways(context.TODO(), client, router.ID, updateOpts).Extract() - if err != nil { - if gophercloud.ResponseCodeIs(err, http.StatusNotFound) { - t.Skipf("UpdateExternalGateways not supported: %v", err) - } - th.AssertNoErr(t, err) - } + th.AssertNoErr(t, err) t.Logf("Successfully updated external gateways of router %s", router.ID) tools.PrintResource(t, updatedRouter) @@ -384,12 +371,7 @@ func TestLayer3RouterExternalGateways(t *testing.T) { } updatedRouter, err = routers.RemoveExternalGateways(context.TODO(), client, router.ID, removeOpts).Extract() - if err != nil { - if gophercloud.ResponseCodeIs(err, http.StatusNotFound) { - t.Skipf("RemoveExternalGateways not supported: %v", err) - } - th.AssertNoErr(t, err) - } + th.AssertNoErr(t, err) t.Logf("Successfully removed external gateways from router %s", router.ID) tools.PrintResource(t, updatedRouter) From 905410a3fcb6f67fda77212ca393325b3c71757b Mon Sep 17 00:00:00 2001 From: Anthony ROUSSEL Date: Thu, 22 Jan 2026 22:57:57 +0100 Subject: [PATCH 313/429] gomod: bump golang to 1.25.6 --- .github/workflows/label-pr.yaml | 3 ++- .github/workflows/lint.yaml | 3 ++- go.mod | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/label-pr.yaml b/.github/workflows/label-pr.yaml index 254af8c502..423ea1fdc6 100644 --- a/.github/workflows/label-pr.yaml +++ b/.github/workflows/label-pr.yaml @@ -26,7 +26,8 @@ jobs: - uses: actions/setup-go@v6 with: - go-version: '1' + go-version-file: 'go.mod' + cache: true - name: Checking Go API Compatibility id: go-apidiff diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 3440a1e0c3..f2e4fafa2b 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -13,7 +13,8 @@ jobs: uses: actions/checkout@v6 - uses: actions/setup-go@v6 with: - go-version: '1' + go-version-file: 'go.mod' + cache: true - name: Run linters run: | make lint diff --git a/go.mod b/go.mod index e4dfa74850..3362dec47e 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/gophercloud/gophercloud/v2 -go 1.24.0 +go 1.25.6 require ( go.yaml.in/yaml/v3 v3.0.4 From d2dde1024c194c9f3f78e336dfe09b8e49c8bbc2 Mon Sep 17 00:00:00 2001 From: eshulman2 Date: Mon, 2 Feb 2026 16:03:09 +0200 Subject: [PATCH 314/429] Use jimmy amphora in octavia job To avoid kvm error in nested virtualization use older amphora image --- .github/workflows/functional-loadbalancer.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/functional-loadbalancer.yaml b/.github/workflows/functional-loadbalancer.yaml index fc18748982..2afdb83f90 100644 --- a/.github/workflows/functional-loadbalancer.yaml +++ b/.github/workflows/functional-loadbalancer.yaml @@ -14,6 +14,8 @@ jobs: openstack_version: "master" ubuntu_version: "24.04" devstack_conf_overrides: | + LIBVIRT_CPU_MODE=host-passthrough + OCTAVIA_AMP_DISTRIBUTION_RELEASE_ID=jammy # ensure we're using a working version of setuptools if [ -n "\$TOP_DIR" ]; then sed -i 's/setuptools\[core\]$/setuptools[core]==79.0.1/g' \$TOP_DIR/lib/infra \$TOP_DIR/inc/python From 67428efe77972332b507f68cb53ae7b0094d2ec8 Mon Sep 17 00:00:00 2001 From: Jacob Anders Date: Wed, 28 Jan 2026 20:07:17 +1000 Subject: [PATCH 315/429] baremetal: Add Health field to Node Add support for the node health field which reports hardware health status from the BMC. Requires Ironic API microversion 1.109. Partially implements metal3-io#2888 Signed-off-by: Jacob Anders Assisted-by: Claude-4.5-opus-high Co-authored-by: Cursor --- openstack/baremetal/v1/nodes/requests.go | 4 ++++ openstack/baremetal/v1/nodes/results.go | 5 +++++ openstack/baremetal/v1/nodes/testing/fixtures_test.go | 3 +++ 3 files changed, 12 insertions(+) diff --git a/openstack/baremetal/v1/nodes/requests.go b/openstack/baremetal/v1/nodes/requests.go index 6268f5037e..89ba6a5b16 100644 --- a/openstack/baremetal/v1/nodes/requests.go +++ b/openstack/baremetal/v1/nodes/requests.go @@ -113,6 +113,10 @@ type ListOpts struct { // Filter the list with the specified fault. Fault string `q:"fault"` + // Filter the list with the specified health status. + // Requires microversion 1.109 or later. + Health string `q:"health"` + // One or more fields to be returned in the response. Fields []string `q:"fields" format:"comma-separated"` diff --git a/openstack/baremetal/v1/nodes/results.go b/openstack/baremetal/v1/nodes/results.go index 06ab429110..e2c5947b7b 100644 --- a/openstack/baremetal/v1/nodes/results.go +++ b/openstack/baremetal/v1/nodes/results.go @@ -139,6 +139,11 @@ type Node struct { // node. There are other possible types, e.g., “clean failure” and “rescue abort failure”. Fault string `json:"fault"` + // Health indicates the hardware health status reported by the BMC. + // Possible values are "OK", "Warning", "Critical", or empty if not available. + // This field is read-only and requires microversion 1.109 or later. + Health string `json:"health"` + // Error from the most recent (last) transaction that started but failed to finish. LastError string `json:"last_error"` diff --git a/openstack/baremetal/v1/nodes/testing/fixtures_test.go b/openstack/baremetal/v1/nodes/testing/fixtures_test.go index 064351ea87..84a6cccb96 100644 --- a/openstack/baremetal/v1/nodes/testing/fixtures_test.go +++ b/openstack/baremetal/v1/nodes/testing/fixtures_test.go @@ -102,6 +102,7 @@ const NodeListDetailBody = ` "extra": {}, "fault": null, "firmware_interface": "no-firmware", + "health": "OK", "inspect_interface": "no-inspect", "inspection_finished_at": null, "inspection_started_at": null, @@ -417,6 +418,7 @@ const SingleNodeBody = ` "extra": {}, "fault": null, "firmware_interface": "no-firmware", + "health": "OK", "inspect_interface": "no-inspect", "inspection_finished_at": null, "inspection_started_at": null, @@ -939,6 +941,7 @@ var ( Maintenance: false, MaintenanceReason: "", Fault: "", + Health: "OK", LastError: "", Reservation: "", Driver: "ipmi", From cafe1ac98cd78f0e528ac08a567afd16fd1e295f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Feb 2026 09:03:00 +0000 Subject: [PATCH 316/429] build(deps): bump golang.org/x/crypto from 0.47.0 to 0.48.0 Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.47.0 to 0.48.0. - [Commits](https://github.com/golang/crypto/compare/v0.47.0...v0.48.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-version: 0.48.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 3362dec47e..2fce7628d9 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.25.6 require ( go.yaml.in/yaml/v3 v3.0.4 - golang.org/x/crypto v0.47.0 + golang.org/x/crypto v0.48.0 ) -require golang.org/x/sys v0.40.0 // indirect +require golang.org/x/sys v0.41.0 // indirect diff --git a/go.sum b/go.sum index aedfcaa0b6..457e8ed0f8 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,10 @@ go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= -golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= -golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= -golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= +golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= +golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg= +golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From f0d41456842f5a440962793826787c575f2bf3e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Thu, 12 Feb 2026 15:03:38 +0100 Subject: [PATCH 317/429] CI: Fix fwaas jobs They were configured to run the whole networking test suite without devstack being configured for it. Furthermore, it's redundant with the networking job. Restore the job to only run the fwaas_v2 tests as it was previous to commit 90cded10439a88581c9cd5afbbca206bc20c3230. --- .github/workflows/functional-fwaas_v2.yaml | 2 +- Makefile | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/functional-fwaas_v2.yaml b/.github/workflows/functional-fwaas_v2.yaml index 50908995bf..be6211ca78 100644 --- a/.github/workflows/functional-fwaas_v2.yaml +++ b/.github/workflows/functional-fwaas_v2.yaml @@ -89,7 +89,7 @@ jobs: if: ${{ fromJSON(steps.changed-files.outputs.matches) }} run: | source ${{ github.workspace }}/script/stackenv - make acceptance-networking + make acceptance-fwaas echo "TESTS_RUN=true" >> $GITHUB_ENV env: DEVSTACK_PATH: ${{ github.workspace }}/devstack diff --git a/Makefile b/Makefile index e5b77e0369..79411c0026 100644 --- a/Makefile +++ b/Makefile @@ -78,6 +78,10 @@ acceptance-dns: $(GO_TEST) -timeout $(TIMEOUT) -tags "fixtures acceptance" ./internal/acceptance/openstack/dns/... .PHONY: acceptance-dns +acceptance-fwaas: + $(GO_TEST) -timeout $(TIMEOUT) -tags "fixtures acceptance" ./internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/... +.PHONY: acceptance-fwaas + acceptance-identity: $(GO_TEST) -timeout $(TIMEOUT) -tags "fixtures acceptance" ./internal/acceptance/openstack/identity/... .PHONY: acceptance-identity From 53881b95501136f55232949581b0a4c2342771e8 Mon Sep 17 00:00:00 2001 From: Omer Date: Mon, 1 Dec 2025 14:10:50 +0200 Subject: [PATCH 318/429] Add TSIG key support for OpenStack DNS v2 API Implement TSIG (Transaction SIGnature) key management for the Designate DNS service, enabling authentication of DNS transactions between servers for zone transfers and dynamic updates. Fixes #3622 Signed-off-by: Omer --- internal/acceptance/openstack/dns/v2/dns.go | 46 ++++ .../openstack/dns/v2/tsigkeys_test.go | 56 +++++ openstack/dns/v2/tsigkeys/doc.go | 72 ++++++ openstack/dns/v2/tsigkeys/requests.go | 158 ++++++++++++ openstack/dns/v2/tsigkeys/results.go | 119 ++++++++++ openstack/dns/v2/tsigkeys/testing/doc.go | 2 + .../dns/v2/tsigkeys/testing/fixtures_test.go | 224 ++++++++++++++++++ .../dns/v2/tsigkeys/testing/requests_test.go | 98 ++++++++ openstack/dns/v2/tsigkeys/urls.go | 13 + 9 files changed, 788 insertions(+) create mode 100644 internal/acceptance/openstack/dns/v2/tsigkeys_test.go create mode 100644 openstack/dns/v2/tsigkeys/doc.go create mode 100644 openstack/dns/v2/tsigkeys/requests.go create mode 100644 openstack/dns/v2/tsigkeys/results.go create mode 100644 openstack/dns/v2/tsigkeys/testing/doc.go create mode 100644 openstack/dns/v2/tsigkeys/testing/fixtures_test.go create mode 100644 openstack/dns/v2/tsigkeys/testing/requests_test.go create mode 100644 openstack/dns/v2/tsigkeys/urls.go diff --git a/internal/acceptance/openstack/dns/v2/dns.go b/internal/acceptance/openstack/dns/v2/dns.go index 9adb61882d..596ce75431 100644 --- a/internal/acceptance/openstack/dns/v2/dns.go +++ b/internal/acceptance/openstack/dns/v2/dns.go @@ -9,6 +9,7 @@ import ( "github.com/gophercloud/gophercloud/v2/openstack/dns/v2/recordsets" transferAccepts "github.com/gophercloud/gophercloud/v2/openstack/dns/v2/transfer/accept" transferRequests "github.com/gophercloud/gophercloud/v2/openstack/dns/v2/transfer/request" + "github.com/gophercloud/gophercloud/v2/openstack/dns/v2/tsigkeys" "github.com/gophercloud/gophercloud/v2/openstack/dns/v2/zones" th "github.com/gophercloud/gophercloud/v2/testhelper" ) @@ -308,3 +309,48 @@ func WaitForZoneStatus(client *gophercloud.ServiceClient, zone *zones.Zone, stat return false, nil }) } + +// CreateTSIGKey will create a TSIG key with a random name. An error will +// be returned if the TSIG key was unable to be created. +func CreateTSIGKey(t *testing.T, client *gophercloud.ServiceClient) (*tsigkeys.TSIGKey, error) { + keyName := tools.RandomString("ACPTTEST", 8) + + t.Logf("Attempting to create TSIG key: %s", keyName) + createOpts := tsigkeys.CreateOpts{ + Name: keyName, + Algorithm: "hmac-sha256", + Secret: "example-test-secret-key==", + Scope: "POOL", + // Default pool ID from designate/conf/central.py + ResourceID: "794ccc2c-d751-44fe-b57f-8894c9f5c842", + } + + tsigkey, err := tsigkeys.Create(context.TODO(), client, createOpts).Extract() + if err != nil { + return tsigkey, err + } + + newTSIGKey, err := tsigkeys.Get(context.TODO(), client, tsigkey.ID).Extract() + if err != nil { + return tsigkey, err + } + + t.Logf("Created TSIG key: %s", keyName) + + th.AssertEquals(t, newTSIGKey.Name, keyName) + th.AssertEquals(t, newTSIGKey.Algorithm, "hmac-sha256") + + return newTSIGKey, nil +} + +// DeleteTSIGKey will delete a specified TSIG key. A fatal error will occur if +// the TSIG key failed to be deleted. This works best when used as a deferred +// function. +func DeleteTSIGKey(t *testing.T, client *gophercloud.ServiceClient, tsigkey *tsigkeys.TSIGKey) { + err := tsigkeys.Delete(context.TODO(), client, tsigkey.ID).ExtractErr() + if err != nil { + t.Fatalf("Unable to delete TSIG key %s: %v", tsigkey.ID, err) + } + + t.Logf("Deleted TSIG key: %s", tsigkey.ID) +} diff --git a/internal/acceptance/openstack/dns/v2/tsigkeys_test.go b/internal/acceptance/openstack/dns/v2/tsigkeys_test.go new file mode 100644 index 0000000000..e07b695be2 --- /dev/null +++ b/internal/acceptance/openstack/dns/v2/tsigkeys_test.go @@ -0,0 +1,56 @@ +//go:build acceptance || dns || tsigkeys + +package v2 + +import ( + "context" + "testing" + + "github.com/gophercloud/gophercloud/v2/internal/acceptance/clients" + "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" + "github.com/gophercloud/gophercloud/v2/openstack/dns/v2/tsigkeys" + th "github.com/gophercloud/gophercloud/v2/testhelper" +) + +func TestTSIGKeysCRUD(t *testing.T) { + clients.RequireAdmin(t) + + client, err := clients.NewDNSV2Client() + th.AssertNoErr(t, err) + + tsigkey, err := CreateTSIGKey(t, client) + th.AssertNoErr(t, err) + defer DeleteTSIGKey(t, client, tsigkey) + + tools.PrintResource(t, &tsigkey) + + allPages, err := tsigkeys.List(client, nil).AllPages(context.TODO()) + th.AssertNoErr(t, err) + + allTSIGKeys, err := tsigkeys.ExtractTSIGKeys(allPages) + th.AssertNoErr(t, err) + + var found bool + for _, k := range allTSIGKeys { + tools.PrintResource(t, &k) + + if tsigkey.Name == k.Name { + found = true + } + } + + th.AssertEquals(t, found, true) + + updateOpts := tsigkeys.UpdateOpts{ + Name: tsigkey.Name + "-updated", + Secret: "updated-test-secret-key==", + } + + newTSIGKey, err := tsigkeys.Update(context.TODO(), client, tsigkey.ID, updateOpts).Extract() + th.AssertNoErr(t, err) + + tools.PrintResource(t, &newTSIGKey) + + th.AssertEquals(t, newTSIGKey.Name, tsigkey.Name+"-updated") + th.AssertEquals(t, newTSIGKey.Secret, "updated-test-secret-key==") +} diff --git a/openstack/dns/v2/tsigkeys/doc.go b/openstack/dns/v2/tsigkeys/doc.go new file mode 100644 index 0000000000..7e99c6dbe4 --- /dev/null +++ b/openstack/dns/v2/tsigkeys/doc.go @@ -0,0 +1,72 @@ +/* +Package tsigkeys provides information and interaction with the TSIG key API +resource for the OpenStack DNS service. + +TSIG (Transaction SIGnature) keys are used to authenticate DNS transactions +between servers, such as zone transfers and dynamic updates. + +Example to List TSIG Keys + + listOpts := tsigkeys.ListOpts{ + Scope: "POOL", + } + + allPages, err := tsigkeys.List(dnsClient, listOpts).AllPages(context.TODO()) + if err != nil { + panic(err) + } + + allTSIGKeys, err := tsigkeys.ExtractTSIGKeys(allPages) + if err != nil { + panic(err) + } + + for _, tsigkey := range allTSIGKeys { + fmt.Printf("%+v\n", tsigkey) + } + +Example to Create a TSIG Key + + createOpts := tsigkeys.CreateOpts{ + Name: "mytsigkey", + Algorithm: "hmac-sha256", + Secret: "example-secret-key-value==", + Scope: "POOL", + ResourceID: "pool-id-here", + } + + tsigkey, err := tsigkeys.Create(context.TODO(), dnsClient, createOpts).Extract() + if err != nil { + panic(err) + } + +Example to Get a TSIG Key + + tsigkeyID := "99d10f68-5623-4491-91a0-6daafa32b60e" + tsigkey, err := tsigkeys.Get(context.TODO(), dnsClient, tsigkeyID).Extract() + if err != nil { + panic(err) + } + +Example to Update a TSIG Key + + tsigkeyID := "99d10f68-5623-4491-91a0-6daafa32b60e" + updateOpts := tsigkeys.UpdateOpts{ + Name: "updatedname", + Secret: "updated-secret-key-value==", + } + + tsigkey, err := tsigkeys.Update(context.TODO(), dnsClient, tsigkeyID, updateOpts).Extract() + if err != nil { + panic(err) + } + +Example to Delete a TSIG Key + + tsigkeyID := "99d10f68-5623-4491-91a0-6daafa32b60e" + err := tsigkeys.Delete(context.TODO(), dnsClient, tsigkeyID).ExtractErr() + if err != nil { + panic(err) + } +*/ +package tsigkeys diff --git a/openstack/dns/v2/tsigkeys/requests.go b/openstack/dns/v2/tsigkeys/requests.go new file mode 100644 index 0000000000..2f8b0a4aa5 --- /dev/null +++ b/openstack/dns/v2/tsigkeys/requests.go @@ -0,0 +1,158 @@ +package tsigkeys + +import ( + "context" + + "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/pagination" +) + +// ListOptsBuilder allows extensions to add parameters to the List request. +type ListOptsBuilder interface { + ToTSIGKeyListQuery() (string, error) +} + +// ListOpts allows the filtering and sorting of paginated collections through +// the API. Filtering is achieved by passing in struct field values that map to +// the server attributes you want to see returned. Marker and Limit are used +// for pagination. +// https://docs.openstack.org/api-ref/dns/ +type ListOpts struct { + // Integer value for the limit of values to return. + Limit int `q:"limit"` + + // UUID of the TSIG key at which you want to set a marker. + Marker string `q:"marker"` + + // Name of the TSIG key. + Name string `q:"name"` + + // Algorithm used by the TSIG key. + Algorithm string `q:"algorithm"` + + // Scope of the TSIG key (ZONE or POOL). + Scope string `q:"scope"` +} + +// ToTSIGKeyListQuery formats a ListOpts into a query string. +func (opts ListOpts) ToTSIGKeyListQuery() (string, error) { + q, err := gophercloud.BuildQueryString(opts) + return q.String(), err +} + +// List implements a TSIG key List request. +func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { + url := baseURL(client) + if opts != nil { + query, err := opts.ToTSIGKeyListQuery() + if err != nil { + return pagination.Pager{Err: err} + } + url += query + } + return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page { + return TSIGKeyPage{pagination.LinkedPageBase{PageResult: r}} + }) +} + +// Get returns information about a TSIG key, given its ID. +func Get(ctx context.Context, client *gophercloud.ServiceClient, tsigkeyID string) (r GetResult) { + resp, err := client.Get(ctx, tsigkeyURL(client, tsigkeyID), &r.Body, nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + +// CreateOptsBuilder allows extensions to add additional attributes to the +// Create request. +type CreateOptsBuilder interface { + ToTSIGKeyCreateMap() (map[string]any, error) +} + +// CreateOpts specifies the attributes used to create a TSIG key. +type CreateOpts struct { + // Name of the TSIG key. + Name string `json:"name" required:"true"` + + // Algorithm is the TSIG algorithm (e.g., hmac-sha256, hmac-sha512). + Algorithm string `json:"algorithm" required:"true"` + + // Secret is the base64-encoded secret key. + Secret string `json:"secret" required:"true"` + + // Scope defines the scope of the TSIG key (ZONE or POOL). + Scope string `json:"scope" required:"true"` + + // ResourceID is the ID of the resource (zone or pool) this key is associated with. + ResourceID string `json:"resource_id" required:"true"` +} + +// ToTSIGKeyCreateMap formats a CreateOpts structure into a request body. +func (opts CreateOpts) ToTSIGKeyCreateMap() (map[string]any, error) { + return gophercloud.BuildRequestBody(opts, "") +} + +// Create implements a TSIG key create request. +func Create(ctx context.Context, client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { + b, err := opts.ToTSIGKeyCreateMap() + if err != nil { + r.Err = err + return + } + resp, err := client.Post(ctx, baseURL(client), &b, &r.Body, &gophercloud.RequestOpts{ + OkCodes: []int{201}, + }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + +// UpdateOptsBuilder allows extensions to add additional attributes to the +// Update request. +type UpdateOptsBuilder interface { + ToTSIGKeyUpdateMap() (map[string]any, error) +} + +// UpdateOpts specifies the attributes to update a TSIG key. +type UpdateOpts struct { + // Name of the TSIG key. + Name string `json:"name,omitempty"` + + // Algorithm is the TSIG algorithm. + Algorithm string `json:"algorithm,omitempty"` + + // Secret is the base64-encoded secret key. + Secret string `json:"secret,omitempty"` + + // Scope defines the scope of the TSIG key. + Scope string `json:"scope,omitempty"` + + // ResourceID is the ID of the resource this key is associated with. + ResourceID string `json:"resource_id,omitempty"` +} + +// ToTSIGKeyUpdateMap formats an UpdateOpts structure into a request body. +func (opts UpdateOpts) ToTSIGKeyUpdateMap() (map[string]any, error) { + return gophercloud.BuildRequestBody(opts, "") +} + +// Update implements a TSIG key update request. +func Update(ctx context.Context, client *gophercloud.ServiceClient, tsigkeyID string, opts UpdateOptsBuilder) (r UpdateResult) { + b, err := opts.ToTSIGKeyUpdateMap() + if err != nil { + r.Err = err + return + } + resp, err := client.Patch(ctx, tsigkeyURL(client, tsigkeyID), &b, &r.Body, &gophercloud.RequestOpts{ + OkCodes: []int{200}, + }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + +// Delete implements a TSIG key delete request. +func Delete(ctx context.Context, client *gophercloud.ServiceClient, tsigkeyID string) (r DeleteResult) { + resp, err := client.Delete(ctx, tsigkeyURL(client, tsigkeyID), &gophercloud.RequestOpts{ + OkCodes: []int{204}, + }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} diff --git a/openstack/dns/v2/tsigkeys/results.go b/openstack/dns/v2/tsigkeys/results.go new file mode 100644 index 0000000000..02382e9b7a --- /dev/null +++ b/openstack/dns/v2/tsigkeys/results.go @@ -0,0 +1,119 @@ +package tsigkeys + +import ( + "encoding/json" + "time" + + "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/pagination" +) + +type commonResult struct { + gophercloud.Result +} + +// Extract interprets a GetResult, CreateResult or UpdateResult as a TSIGKey. +// An error is returned if the original call or the extraction failed. +func (r commonResult) Extract() (*TSIGKey, error) { + var s *TSIGKey + err := r.ExtractInto(&s) + return s, err +} + +// CreateResult is the result of a Create request. Call its Extract method +// to interpret the result as a TSIGKey. +type CreateResult struct { + commonResult +} + +// GetResult is the result of a Get request. Call its Extract method +// to interpret the result as a TSIGKey. +type GetResult struct { + commonResult +} + +// UpdateResult is the result of an Update request. Call its Extract method +// to interpret the result as a TSIGKey. +type UpdateResult struct { + commonResult +} + +// DeleteResult is the result of a Delete request. Call its ExtractErr method +// to determine if the request succeeded or failed. +type DeleteResult struct { + gophercloud.ErrResult +} + +// TSIGKeyPage is a single page of TSIGKey results. +type TSIGKeyPage struct { + pagination.LinkedPageBase +} + +// IsEmpty returns true if the page contains no results. +func (r TSIGKeyPage) IsEmpty() (bool, error) { + if r.StatusCode == 204 { + return true, nil + } + + s, err := ExtractTSIGKeys(r) + return len(s) == 0, err +} + +// ExtractTSIGKeys extracts a slice of TSIGKeys from a List result. +func ExtractTSIGKeys(r pagination.Page) ([]TSIGKey, error) { + var s struct { + TSIGKeys []TSIGKey `json:"tsigkeys"` + } + err := (r.(TSIGKeyPage)).ExtractInto(&s) + return s.TSIGKeys, err +} + +// TSIGKey represents a TSIG key for DNS transaction authentication. +type TSIGKey struct { + // ID uniquely identifies this TSIG key. + ID string `json:"id"` + + // Name is the name of the TSIG key. + Name string `json:"name"` + + // Algorithm is the TSIG algorithm used (e.g., hmac-sha256, hmac-sha512). + Algorithm string `json:"algorithm"` + + // Secret is the base64-encoded secret key. + Secret string `json:"secret"` + + // Scope defines the scope of the TSIG key (ZONE or POOL). + Scope string `json:"scope"` + + // ResourceID is the ID of the resource (zone or pool) this key is associated with. + ResourceID string `json:"resource_id"` + + // CreatedAt is the date when the TSIG key was created. + CreatedAt time.Time `json:"-"` + + // UpdatedAt is the date when the TSIG key was last updated. + UpdatedAt time.Time `json:"-"` + + // Links includes HTTP references to the itself. + Links map[string]any `json:"links"` +} + +func (r *TSIGKey) UnmarshalJSON(b []byte) error { + type tmp TSIGKey + var s struct { + tmp + CreatedAt gophercloud.JSONRFC3339MilliNoZ `json:"created_at"` + UpdatedAt gophercloud.JSONRFC3339MilliNoZ `json:"updated_at"` + } + + err := json.Unmarshal(b, &s) + if err != nil { + return err + } + *r = TSIGKey(s.tmp) + + r.CreatedAt = time.Time(s.CreatedAt) + r.UpdatedAt = time.Time(s.UpdatedAt) + + return nil +} diff --git a/openstack/dns/v2/tsigkeys/testing/doc.go b/openstack/dns/v2/tsigkeys/testing/doc.go new file mode 100644 index 0000000000..6f54fc2d97 --- /dev/null +++ b/openstack/dns/v2/tsigkeys/testing/doc.go @@ -0,0 +1,2 @@ +// tsigkeys unit tests +package testing diff --git a/openstack/dns/v2/tsigkeys/testing/fixtures_test.go b/openstack/dns/v2/tsigkeys/testing/fixtures_test.go new file mode 100644 index 0000000000..dc15e74197 --- /dev/null +++ b/openstack/dns/v2/tsigkeys/testing/fixtures_test.go @@ -0,0 +1,224 @@ +package testing + +import ( + "fmt" + "net/http" + "testing" + "time" + + "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/openstack/dns/v2/tsigkeys" + th "github.com/gophercloud/gophercloud/v2/testhelper" + "github.com/gophercloud/gophercloud/v2/testhelper/client" +) + +// ListOutput is a sample response to a List call. +const ListOutput = ` +{ + "links": { + "self": "http://example.com:9001/v2/tsigkeys" + }, + "metadata": { + "total_count": 2 + }, + "tsigkeys": [ + { + "id": "8add45a3-0f29-489f-854e-7609baf8d7a1", + "name": "poolsecondarykey", + "algorithm": "hmac-sha256", + "secret": "my-base64-secret-example==", + "scope": "POOL", + "resource_id": "adcc2fb6-7984-4453-a6f9-2cc2a24a38bb", + "created_at": "2025-08-13T15:54:18.000000", + "updated_at": null, + "links": { + "self": "http://127.0.0.1:9001/v2/tsigkeys/8add45a3-0f29-489f-854e-7609baf8d7a1" + } + }, + { + "id": "9bef46b4-1f3a-59a0-965f-8710caf9e8b2", + "name": "zonekey", + "algorithm": "hmac-sha512", + "secret": "another-base64-secret-example==", + "scope": "ZONE", + "resource_id": "c4d5e6f7-8a9b-0c1d-2e3f-4a5b6c7d8e9f", + "created_at": "2025-08-14T10:30:45.000000", + "updated_at": "2025-08-15T14:22:33.000000", + "links": { + "self": "http://127.0.0.1:9001/v2/tsigkeys/9bef46b4-1f3a-59a0-965f-8710caf9e8b2" + } + } + ] +} +` + +// GetOutput is a sample response to a Get call. +const GetOutput = ` +{ + "id": "8add45a3-0f29-489f-854e-7609baf8d7a1", + "name": "poolsecondarykey", + "algorithm": "hmac-sha256", + "secret": "my-base64-secret-example==", + "scope": "POOL", + "resource_id": "adcc2fb6-7984-4453-a6f9-2cc2a24a38bb", + "created_at": "2025-08-13T15:54:18.000000", + "updated_at": null, + "links": { + "self": "http://127.0.0.1:9001/v2/tsigkeys/8add45a3-0f29-489f-854e-7609baf8d7a1" + } +} +` + +// FirstTSIGKeyCreatedAt is the created at time for the first TSIG key +var FirstTSIGKeyCreatedAt, _ = time.Parse(gophercloud.RFC3339MilliNoZ, "2025-08-13T15:54:18.000000") + +// FirstTSIGKey is the first result in ListOutput +var FirstTSIGKey = tsigkeys.TSIGKey{ + ID: "8add45a3-0f29-489f-854e-7609baf8d7a1", + Name: "poolsecondarykey", + Algorithm: "hmac-sha256", + Secret: "my-base64-secret-example==", + Scope: "POOL", + ResourceID: "adcc2fb6-7984-4453-a6f9-2cc2a24a38bb", + CreatedAt: FirstTSIGKeyCreatedAt, + Links: map[string]any{ + "self": "http://127.0.0.1:9001/v2/tsigkeys/8add45a3-0f29-489f-854e-7609baf8d7a1", + }, +} + +var SecondTSIGKeyCreatedAt, _ = time.Parse(gophercloud.RFC3339MilliNoZ, "2025-08-14T10:30:45.000000") +var SecondTSIGKeyUpdatedAt, _ = time.Parse(gophercloud.RFC3339MilliNoZ, "2025-08-15T14:22:33.000000") + +var SecondTSIGKey = tsigkeys.TSIGKey{ + ID: "9bef46b4-1f3a-59a0-965f-8710caf9e8b2", + Name: "zonekey", + Algorithm: "hmac-sha512", + Secret: "another-base64-secret-example==", + Scope: "ZONE", + ResourceID: "c4d5e6f7-8a9b-0c1d-2e3f-4a5b6c7d8e9f", + CreatedAt: SecondTSIGKeyCreatedAt, + UpdatedAt: SecondTSIGKeyUpdatedAt, + Links: map[string]any{ + "self": "http://127.0.0.1:9001/v2/tsigkeys/9bef46b4-1f3a-59a0-965f-8710caf9e8b2", + }, +} + +// ExpectedTSIGKeysSlice is the slice of results that should be parsed +// from ListOutput, in the expected order. +var ExpectedTSIGKeysSlice = []tsigkeys.TSIGKey{FirstTSIGKey, SecondTSIGKey} + +// HandleListSuccessfully configures the test server to respond to a List request. +func HandleListSuccessfully(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/tsigkeys", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + fmt.Fprint(w, ListOutput) + }) +} + +// HandleGetSuccessfully configures the test server to respond to a Get request. +func HandleGetSuccessfully(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/tsigkeys/8add45a3-0f29-489f-854e-7609baf8d7a1", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + fmt.Fprint(w, GetOutput) + }) +} + +// CreateTSIGKeyRequest is a sample request to create a TSIG key. +const CreateTSIGKeyRequest = ` +{ + "name": "poolsecondarykey", + "algorithm": "hmac-sha256", + "secret": "my-base64-secret-example==", + "scope": "POOL", + "resource_id": "adcc2fb6-7984-4453-a6f9-2cc2a24a38bb" +} +` + +// CreateTSIGKeyResponse is a sample response to a create request. +const CreateTSIGKeyResponse = ` +{ + "id": "8add45a3-0f29-489f-854e-7609baf8d7a1", + "name": "poolsecondarykey", + "algorithm": "hmac-sha256", + "secret": "my-base64-secret-example==", + "scope": "POOL", + "resource_id": "adcc2fb6-7984-4453-a6f9-2cc2a24a38bb", + "created_at": "2025-08-13T15:54:18.000000", + "updated_at": null, + "links": { + "self": "http://127.0.0.1:9001/v2/tsigkeys/8add45a3-0f29-489f-854e-7609baf8d7a1" + } +} +` + +// CreatedTSIGKey is the expected created TSIG key +var CreatedTSIGKey = FirstTSIGKey + +// HandleCreateSuccessfully configures the test server to respond to a Create request. +func HandleCreateSuccessfully(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/tsigkeys", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.TestJSONRequest(t, r, CreateTSIGKeyRequest) + + w.WriteHeader(http.StatusCreated) + w.Header().Add("Content-Type", "application/json") + fmt.Fprint(w, CreateTSIGKeyResponse) + }) +} + +// UpdateTSIGKeyRequest is a sample request to update a TSIG key. +const UpdateTSIGKeyRequest = ` +{ + "name": "updatedsecondarykey", + "secret": "new-base64-secret-example==" +} +` + +// UpdateTSIGKeyResponse is a sample response to update a TSIG key. +const UpdateTSIGKeyResponse = ` +{ + "id": "8add45a3-0f29-489f-854e-7609baf8d7a1", + "name": "updatedsecondarykey", + "algorithm": "hmac-sha256", + "secret": "new-base64-secret-example==", + "scope": "POOL", + "resource_id": "adcc2fb6-7984-4453-a6f9-2cc2a24a38bb", + "created_at": "2025-08-13T15:54:18.000000", + "updated_at": "2025-08-16T09:15:22.000000", + "links": { + "self": "http://127.0.0.1:9001/v2/tsigkeys/8add45a3-0f29-489f-854e-7609baf8d7a1" + } +} +` + +// HandleUpdateSuccessfully configures the test server to respond to an Update request. +func HandleUpdateSuccessfully(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/tsigkeys/8add45a3-0f29-489f-854e-7609baf8d7a1", + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "PATCH") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.TestJSONRequest(t, r, UpdateTSIGKeyRequest) + + w.WriteHeader(http.StatusOK) + w.Header().Add("Content-Type", "application/json") + fmt.Fprint(w, UpdateTSIGKeyResponse) + }) +} + +// HandleDeleteSuccessfully configures the test server to respond to a Delete request. +func HandleDeleteSuccessfully(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/tsigkeys/8add45a3-0f29-489f-854e-7609baf8d7a1", + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "DELETE") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.WriteHeader(http.StatusNoContent) + }) +} diff --git a/openstack/dns/v2/tsigkeys/testing/requests_test.go b/openstack/dns/v2/tsigkeys/testing/requests_test.go new file mode 100644 index 0000000000..3bc163d5b4 --- /dev/null +++ b/openstack/dns/v2/tsigkeys/testing/requests_test.go @@ -0,0 +1,98 @@ +package testing + +import ( + "context" + "testing" + + "github.com/gophercloud/gophercloud/v2/openstack/dns/v2/tsigkeys" + "github.com/gophercloud/gophercloud/v2/pagination" + th "github.com/gophercloud/gophercloud/v2/testhelper" + "github.com/gophercloud/gophercloud/v2/testhelper/client" +) + +func TestList(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + HandleListSuccessfully(t, fakeServer) + + count := 0 + err := tsigkeys.List(client.ServiceClient(fakeServer), nil).EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) { + count++ + actual, err := tsigkeys.ExtractTSIGKeys(page) + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, ExpectedTSIGKeysSlice, actual) + + return true, nil + }) + th.AssertNoErr(t, err) + th.CheckEquals(t, 1, count) +} + +func TestListAllPages(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + HandleListSuccessfully(t, fakeServer) + + allPages, err := tsigkeys.List(client.ServiceClient(fakeServer), nil).AllPages(context.TODO()) + th.AssertNoErr(t, err) + allTSIGKeys, err := tsigkeys.ExtractTSIGKeys(allPages) + th.AssertNoErr(t, err) + th.CheckEquals(t, 2, len(allTSIGKeys)) +} + +func TestGet(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + HandleGetSuccessfully(t, fakeServer) + + actual, err := tsigkeys.Get(context.TODO(), client.ServiceClient(fakeServer), "8add45a3-0f29-489f-854e-7609baf8d7a1").Extract() + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, &FirstTSIGKey, actual) +} + +func TestCreate(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + HandleCreateSuccessfully(t, fakeServer) + + createOpts := tsigkeys.CreateOpts{ + Name: "poolsecondarykey", + Algorithm: "hmac-sha256", + Secret: "my-base64-secret-example==", + Scope: "POOL", + ResourceID: "adcc2fb6-7984-4453-a6f9-2cc2a24a38bb", + } + + actual, err := tsigkeys.Create(context.TODO(), client.ServiceClient(fakeServer), createOpts).Extract() + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, &CreatedTSIGKey, actual) +} + +func TestUpdate(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + HandleUpdateSuccessfully(t, fakeServer) + + updateOpts := tsigkeys.UpdateOpts{ + Name: "updatedsecondarykey", + Secret: "new-base64-secret-example==", + } + + UpdatedTSIGKey := CreatedTSIGKey + UpdatedTSIGKey.Name = "updatedsecondarykey" + UpdatedTSIGKey.Secret = "new-base64-secret-example==" + + actual, err := tsigkeys.Update(context.TODO(), client.ServiceClient(fakeServer), UpdatedTSIGKey.ID, updateOpts).Extract() + th.AssertNoErr(t, err) + th.CheckEquals(t, UpdatedTSIGKey.Name, actual.Name) + th.CheckEquals(t, UpdatedTSIGKey.Secret, actual.Secret) +} + +func TestDelete(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + HandleDeleteSuccessfully(t, fakeServer) + + err := tsigkeys.Delete(context.TODO(), client.ServiceClient(fakeServer), "8add45a3-0f29-489f-854e-7609baf8d7a1").ExtractErr() + th.AssertNoErr(t, err) +} diff --git a/openstack/dns/v2/tsigkeys/urls.go b/openstack/dns/v2/tsigkeys/urls.go new file mode 100644 index 0000000000..f7c4b0cfe3 --- /dev/null +++ b/openstack/dns/v2/tsigkeys/urls.go @@ -0,0 +1,13 @@ +package tsigkeys + +import "github.com/gophercloud/gophercloud/v2" + +// baseURL returns the base URL for TSIG keys. +func baseURL(c *gophercloud.ServiceClient) string { + return c.ServiceURL("tsigkeys") +} + +// tsigkeyURL returns the URL for a specific TSIG key. +func tsigkeyURL(c *gophercloud.ServiceClient, tsigkeyID string) string { + return c.ServiceURL("tsigkeys", tsigkeyID) +} From 0b45b510ae393b51fa707ef0b188af5e8963a5fa Mon Sep 17 00:00:00 2001 From: Winicius Silva Date: Thu, 19 Feb 2026 17:18:58 +0000 Subject: [PATCH 319/429] remove description from ListOpts --- .../layer3/addressscopes/requests.go | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/openstack/networking/v2/extensions/layer3/addressscopes/requests.go b/openstack/networking/v2/extensions/layer3/addressscopes/requests.go index 22e4df39de..d75a3f0581 100644 --- a/openstack/networking/v2/extensions/layer3/addressscopes/requests.go +++ b/openstack/networking/v2/extensions/layer3/addressscopes/requests.go @@ -20,17 +20,16 @@ type ListOptsBuilder interface { // SortDir sets the direction, and is either `asc' or `desc'. // Marker and Limit are used for the pagination. type ListOpts struct { - ID string `q:"id"` - Name string `q:"name"` - TenantID string `q:"tenant_id"` - ProjectID string `q:"project_id"` - IPVersion int `q:"ip_version"` - Shared *bool `q:"shared"` - Description string `q:"description"` - Limit int `q:"limit"` - Marker string `q:"marker"` - SortKey string `q:"sort_key"` - SortDir string `q:"sort_dir"` + ID string `q:"id"` + Name string `q:"name"` + TenantID string `q:"tenant_id"` + ProjectID string `q:"project_id"` + IPVersion int `q:"ip_version"` + Shared *bool `q:"shared"` + Limit int `q:"limit"` + Marker string `q:"marker"` + SortKey string `q:"sort_key"` + SortDir string `q:"sort_dir"` } // ToAddressScopeListQuery formats a ListOpts into a query string. From 7f478e145f769faf73576712a1336344e9635d93 Mon Sep 17 00:00:00 2001 From: Bertrand Lanson Date: Tue, 3 Mar 2026 21:14:23 +0100 Subject: [PATCH 320/429] fix: networkipavailabilities: handle scientific notation in IP counts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Go's JSON decoder converts large integers to float64 when decoding into interface{}, which causes values ≥ 1e21 to be re-encoded in scientific notation. big.Int cannot parse that notation, crashing any List() call that includes a network with a large IPv6 prefix such as /56 or shorter. Signed-off-by: Bertrand Lanson --- .../networkipavailabilities/results.go | 62 ++++++++++++++++--- .../testing/fixtures_test.go | 14 +++-- 2 files changed, 61 insertions(+), 15 deletions(-) diff --git a/openstack/networking/v2/extensions/networkipavailabilities/results.go b/openstack/networking/v2/extensions/networkipavailabilities/results.go index b37617f9d1..e29810972a 100644 --- a/openstack/networking/v2/extensions/networkipavailabilities/results.go +++ b/openstack/networking/v2/extensions/networkipavailabilities/results.go @@ -2,6 +2,7 @@ package networkipavailabilities import ( "encoding/json" + "fmt" "math/big" "github.com/gophercloud/gophercloud/v2" @@ -52,12 +53,35 @@ type NetworkIPAvailability struct { UsedIPs string `json:"-"` } +// Go's encoding/json decodes all JSON numbers into float64 when the target is +// interface{}. For large integers (abs >= 1e21), re-encoding that float64 +// produces scientific notation (e.g. "1.1805916207174113e+21"), which +// big.Int.UnmarshalJSON cannot parse. This function handles both plain integer +// and scientific notation forms. +func parseBigIntFromNumber(n json.Number) (*big.Int, error) { + s := string(n) + + // Fast path: plain integer notation + bi := new(big.Int) + if _, ok := bi.SetString(s, 10); ok { + return bi, nil + } + + // Slow path: scientific notation from float64 round-trip + bf := new(big.Float).SetPrec(256) + if _, _, err := bf.Parse(s, 10); err != nil { + return nil, fmt.Errorf("networkipavailabilities: cannot parse %q as an integer: %w", s, err) + } + result, _ := bf.Int(nil) + return result, nil +} + func (r *NetworkIPAvailability) UnmarshalJSON(b []byte) error { type tmp NetworkIPAvailability var s struct { tmp - TotalIPs big.Int `json:"total_ips"` - UsedIPs big.Int `json:"used_ips"` + TotalIPs json.Number `json:"total_ips"` + UsedIPs json.Number `json:"used_ips"` } err := json.Unmarshal(b, &s) @@ -66,10 +90,19 @@ func (r *NetworkIPAvailability) UnmarshalJSON(b []byte) error { } *r = NetworkIPAvailability(s.tmp) - r.TotalIPs = s.TotalIPs.String() - r.UsedIPs = s.UsedIPs.String() + totalIPs, err := parseBigIntFromNumber(s.TotalIPs) + if err != nil { + return err + } + r.TotalIPs = totalIPs.String() - return err + usedIPs, err := parseBigIntFromNumber(s.UsedIPs) + if err != nil { + return err + } + r.UsedIPs = usedIPs.String() + + return nil } // SubnetIPAvailability represents availability details for a single subnet. @@ -97,8 +130,8 @@ func (r *SubnetIPAvailability) UnmarshalJSON(b []byte) error { type tmp SubnetIPAvailability var s struct { tmp - TotalIPs big.Int `json:"total_ips"` - UsedIPs big.Int `json:"used_ips"` + TotalIPs json.Number `json:"total_ips"` + UsedIPs json.Number `json:"used_ips"` } err := json.Unmarshal(b, &s) @@ -107,10 +140,19 @@ func (r *SubnetIPAvailability) UnmarshalJSON(b []byte) error { } *r = SubnetIPAvailability(s.tmp) - r.TotalIPs = s.TotalIPs.String() - r.UsedIPs = s.UsedIPs.String() + totalIPs, err := parseBigIntFromNumber(s.TotalIPs) + if err != nil { + return err + } + r.TotalIPs = totalIPs.String() + + usedIPs, err := parseBigIntFromNumber(s.UsedIPs) + if err != nil { + return err + } + r.UsedIPs = usedIPs.String() - return err + return nil } // NetworkIPAvailabilityPage stores a single page of NetworkIPAvailabilities diff --git a/openstack/networking/v2/extensions/networkipavailabilities/testing/fixtures_test.go b/openstack/networking/v2/extensions/networkipavailabilities/testing/fixtures_test.go index 58900db23c..475511cce2 100644 --- a/openstack/networking/v2/extensions/networkipavailabilities/testing/fixtures_test.go +++ b/openstack/networking/v2/extensions/networkipavailabilities/testing/fixtures_test.go @@ -15,11 +15,11 @@ const NetworkIPAvailabilityListResult = ` "project_id": "fb57277ef2f84a0e85b9018ec2dedbf7", "subnet_ip_availability": [ { - "cidr": "fdbc:bf53:567e::/64", + "cidr": "fdbc:bf53:567e::/56", "ip_version": 6, "subnet_id": "497ac4d3-0b92-42cf-82de-71302ab2b656", "subnet_name": "ipv6-private-subnet", - "total_ips": 18446744073709552000, + "total_ips": 4722366482869645213696, "used_ips": 2 }, { @@ -69,10 +69,14 @@ var NetworkIPAvailability1 = networkipavailabilities.NetworkIPAvailability{ { SubnetID: "497ac4d3-0b92-42cf-82de-71302ab2b656", SubnetName: "ipv6-private-subnet", - CIDR: "fdbc:bf53:567e::/64", + CIDR: "fdbc:bf53:567e::/56", IPVersion: int(gophercloud.IPv6), - TotalIPs: "18446744073709552000", - UsedIPs: "2", + // 4722366482869645213696 is 2^72 (a /56 IPv6 subnet). + // After gophercloud's float64 round-trip (numbers >= 1e21 are + // re-encoded in scientific notation), the value loses the last + // few digits of precision but no longer crashes. + TotalIPs: "4722366482869645000000", + UsedIPs: "2", }, { SubnetID: "521f47e7-c4fb-452c-b71a-851da38cc571", From 421f7d4af2830a2f1ed2078fcb0b1fc9cc6f4e10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Tue, 10 Mar 2026 09:20:14 +0100 Subject: [PATCH 321/429] Do not specify go patch version There's no good reason for this, and makes it harder to consume. --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 2fce7628d9..f1415ecc13 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/gophercloud/gophercloud/v2 -go 1.25.6 +go 1.25.0 require ( go.yaml.in/yaml/v3 v3.0.4 From 1cb9d1c03b2c4d64fe508ddcbc010a52804c4388 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Mar 2026 09:02:59 +0000 Subject: [PATCH 322/429] build(deps): bump golang.org/x/crypto from 0.48.0 to 0.49.0 Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.48.0 to 0.49.0. - [Commits](https://github.com/golang/crypto/compare/v0.48.0...v0.49.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-version: 0.49.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index f1415ecc13..2c668ddd43 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.25.0 require ( go.yaml.in/yaml/v3 v3.0.4 - golang.org/x/crypto v0.48.0 + golang.org/x/crypto v0.49.0 ) -require golang.org/x/sys v0.41.0 // indirect +require golang.org/x/sys v0.42.0 // indirect diff --git a/go.sum b/go.sum index 457e8ed0f8..53ebe91e84 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,10 @@ go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= -golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= -golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg= -golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= +golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= +golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU= +golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 74130d7edf09ac2e7626adf422c84b7384ab1e3c Mon Sep 17 00:00:00 2001 From: jlarriba Date: Tue, 10 Mar 2026 13:07:45 +0100 Subject: [PATCH 323/429] Fix clouds.yaml search path to use XDG convention on all platforms os.UserConfigDir() returns ~/Library/Application Support on macOS, which doesn't match the OpenStack standard. Use XDG_CONFIG_HOME with a ~/.config fallback instead. --- openstack/config/clouds/clouds.go | 12 ++- openstack/config/clouds/clouds_test.go | 113 +++++++++++++++++++++++++ 2 files changed, 122 insertions(+), 3 deletions(-) diff --git a/openstack/config/clouds/clouds.go b/openstack/config/clouds/clouds.go index 94c01645d9..a8eb357f7d 100644 --- a/openstack/config/clouds/clouds.go +++ b/openstack/config/clouds/clouds.go @@ -81,9 +81,15 @@ func Parse(opts ...ParseOption) (gophercloud.AuthOptions, gophercloud.EndpointOp if err != nil { return gophercloud.AuthOptions{}, gophercloud.EndpointOpts{}, nil, fmt.Errorf("failed to get the current working directory: %w", err) } - userConfig, err := os.UserConfigDir() - if err != nil { - return gophercloud.AuthOptions{}, gophercloud.EndpointOpts{}, nil, fmt.Errorf("failed to get the user config directory: %w", err) + // Use XDG_CONFIG_HOME or fall back to ~/.config, matching the + // OpenStack convention for clouds.yaml location on all platforms. + userConfig := os.Getenv("XDG_CONFIG_HOME") + if userConfig == "" { + homeDir, err := os.UserHomeDir() + if err != nil { + return gophercloud.AuthOptions{}, gophercloud.EndpointOpts{}, nil, fmt.Errorf("failed to get the user home directory: %w", err) + } + userConfig = path.Join(homeDir, ".config") } options.locations = []string{path.Join(cwd, "clouds.yaml"), path.Join(userConfig, "openstack", "clouds.yaml"), path.Join("/etc", "openstack", "clouds.yaml")} } diff --git a/openstack/config/clouds/clouds_test.go b/openstack/config/clouds/clouds_test.go index 384aea92d8..bd705833af 100644 --- a/openstack/config/clouds/clouds_test.go +++ b/openstack/config/clouds/clouds_test.go @@ -173,6 +173,119 @@ func TestParse(t *testing.T) { } }) + t.Run("uses XDG_CONFIG_HOME for clouds.yaml location", func(t *testing.T) { + const cloudsYAML = `clouds: + gophercloud-test: + auth: + auth_url: https://example.com/xdg-config:13000` + + // Create a temp dir to use as XDG_CONFIG_HOME with clouds.yaml inside. + xdgDir, err := os.MkdirTemp(os.TempDir(), tempDirPrefix) + if err != nil { + t.Fatalf("unable to create a temporary directory: %v", err) + } + defer rmTmpDirOrPanic(xdgDir) + + openstackDir := path.Join(xdgDir, "openstack") + if err := os.MkdirAll(openstackDir, 0755); err != nil { + t.Fatalf("unable to create openstack config directory: %v", err) + } + if err := os.WriteFile(path.Join(openstackDir, "clouds.yaml"), []byte(cloudsYAML), 0644); err != nil { + t.Fatalf("unable to create a mock clouds.yaml file: %v", err) + } + + // Change to an empty temp dir so cwd has no clouds.yaml. + emptyDir, err := os.MkdirTemp(os.TempDir(), tempDirPrefix) + if err != nil { + t.Fatalf("unable to create a temporary directory: %v", err) + } + defer rmTmpDirOrPanic(emptyDir) + + cwd, err := os.Getwd() + if err != nil { + t.Fatalf("unable to determine the current working directory: %v", err) + } + if err := os.Chdir(emptyDir); err != nil { + t.Fatalf("unable to move to a temporary directory: %v", err) + } + defer func() { + if err := os.Chdir(cwd); err != nil { + panic("unable to reset the current working directory: " + err.Error()) + } + }() + + t.Setenv("XDG_CONFIG_HOME", xdgDir) + t.Setenv("OS_CLIENT_CONFIG_FILE", "") + + ao, _, _, err := clouds.Parse( + clouds.WithCloudName("gophercloud-test"), + ) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + if got := ao.IdentityEndpoint; got != "https://example.com/xdg-config:13000" { + t.Errorf("unexpected identity endpoint: %q", got) + } + }) + + t.Run("falls back to ~/.config when XDG_CONFIG_HOME is not set", func(t *testing.T) { + const cloudsYAML = `clouds: + gophercloud-test: + auth: + auth_url: https://example.com/home-config:13000` + + // Create a temp dir to use as HOME with clouds.yaml in .config/openstack/. + homeDir, err := os.MkdirTemp(os.TempDir(), tempDirPrefix) + if err != nil { + t.Fatalf("unable to create a temporary directory: %v", err) + } + defer rmTmpDirOrPanic(homeDir) + + openstackDir := path.Join(homeDir, ".config", "openstack") + if err := os.MkdirAll(openstackDir, 0755); err != nil { + t.Fatalf("unable to create openstack config directory: %v", err) + } + if err := os.WriteFile(path.Join(openstackDir, "clouds.yaml"), []byte(cloudsYAML), 0644); err != nil { + t.Fatalf("unable to create a mock clouds.yaml file: %v", err) + } + + // Change to an empty temp dir so cwd has no clouds.yaml. + emptyDir, err := os.MkdirTemp(os.TempDir(), tempDirPrefix) + if err != nil { + t.Fatalf("unable to create a temporary directory: %v", err) + } + defer rmTmpDirOrPanic(emptyDir) + + cwd, err := os.Getwd() + if err != nil { + t.Fatalf("unable to determine the current working directory: %v", err) + } + if err := os.Chdir(emptyDir); err != nil { + t.Fatalf("unable to move to a temporary directory: %v", err) + } + defer func() { + if err := os.Chdir(cwd); err != nil { + panic("unable to reset the current working directory: " + err.Error()) + } + }() + + t.Setenv("XDG_CONFIG_HOME", "") + t.Setenv("HOME", homeDir) + t.Setenv("OS_CLIENT_CONFIG_FILE", "") + + ao, _, _, err := clouds.Parse( + clouds.WithCloudName("gophercloud-test"), + ) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + if got := ao.IdentityEndpoint; got != "https://example.com/home-config:13000" { + t.Errorf("unexpected identity endpoint: %q", got) + } + }) + t.Run("falls back to the next location if clouds.yaml is not found", func(t *testing.T) { const cloudsYAML1 = `clouds: gophercloud-test: From 89a59ae20fd6c2176833792a7e3eaab8880bdce8 Mon Sep 17 00:00:00 2001 From: Juan Larriba Date: Mon, 23 Mar 2026 11:09:25 +0100 Subject: [PATCH 324/429] Use jammy amphora in octavia epoxy job --- .github/workflows/functional-loadbalancer.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/functional-loadbalancer.yaml b/.github/workflows/functional-loadbalancer.yaml index 2afdb83f90..8740cf21ce 100644 --- a/.github/workflows/functional-loadbalancer.yaml +++ b/.github/workflows/functional-loadbalancer.yaml @@ -24,6 +24,9 @@ jobs: - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" + devstack_conf_overrides: | + LIBVIRT_CPU_MODE=host-passthrough + OCTAVIA_AMP_DISTRIBUTION_RELEASE_ID=jammy - name: "dalmatian" openstack_version: "stable/2024.2" ubuntu_version: "22.04" From 3b0490f4445fbe5f6f06772d83448849dbb4a6ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Wed, 25 Mar 2026 11:28:49 +0100 Subject: [PATCH 325/429] ci: fix unsound condition in label-issue workflow The condition was using separate ${{ }} expressions around an == operator, which expands to a non-empty string that always evaluates to true. Move the comparison inside a single expression so it evaluates correctly as a boolean. Reported by zizmor (unsound-condition). --- .github/workflows/label-issue.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/label-issue.yaml b/.github/workflows/label-issue.yaml index 45ab4cbe34..cb5e84e897 100644 --- a/.github/workflows/label-issue.yaml +++ b/.github/workflows/label-issue.yaml @@ -7,7 +7,7 @@ on: jobs: clear_needinfo: name: Clear needinfo - if: ${{ github.event.issue.user.login }} == ${{ github.event.comment.user.login }} + if: ${{ github.event.issue.user.login == github.event.comment.user.login }} runs-on: ubuntu-latest permissions: issues: write From 02253dd2cc1dfa646605934f55278bc04a0ab385 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Wed, 25 Mar 2026 11:30:01 +0100 Subject: [PATCH 326/429] ci: add persist-credentials: false to all checkout steps Prevent the GitHub token from being persisted in the git config after checkout. This avoids potential credential leakage through artifacts or subsequent steps that don't need repository access. Reported by zizmor (artipacked). --- .github/workflows/codeql-analysis.yaml | 2 ++ .github/workflows/ensure-labels.yaml | 2 ++ .github/workflows/functional-baremetal.yaml | 2 ++ .github/workflows/functional-basic.yaml | 2 ++ .github/workflows/functional-blockstorage.yaml | 2 ++ .github/workflows/functional-compute.yaml | 2 ++ .github/workflows/functional-containerinfra.yaml | 2 ++ .github/workflows/functional-dns.yaml | 2 ++ .github/workflows/functional-fwaas_v2.yaml | 2 ++ .github/workflows/functional-identity.yaml | 2 ++ .github/workflows/functional-image.yaml | 2 ++ .github/workflows/functional-keymanager.yaml | 2 ++ .github/workflows/functional-loadbalancer.yaml | 2 ++ .github/workflows/functional-messaging.yaml | 2 ++ .github/workflows/functional-networking.yaml | 2 ++ .github/workflows/functional-objectstorage.yaml | 2 ++ .github/workflows/functional-orchestration.yaml | 2 ++ .github/workflows/functional-placement.yaml | 2 ++ .github/workflows/functional-sharedfilesystems.yaml | 2 ++ .github/workflows/functional-workflow.yaml | 2 ++ .github/workflows/label-pr.yaml | 1 + .github/workflows/lint.yaml | 2 ++ .github/workflows/unit.yaml | 2 ++ 23 files changed, 45 insertions(+) diff --git a/.github/workflows/codeql-analysis.yaml b/.github/workflows/codeql-analysis.yaml index 90765a6eca..dabe73a738 100644 --- a/.github/workflows/codeql-analysis.yaml +++ b/.github/workflows/codeql-analysis.yaml @@ -19,6 +19,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v6 + with: + persist-credentials: false - name: Setup Go uses: actions/setup-go@v6 diff --git a/.github/workflows/ensure-labels.yaml b/.github/workflows/ensure-labels.yaml index 907a7b8733..e881954b42 100644 --- a/.github/workflows/ensure-labels.yaml +++ b/.github/workflows/ensure-labels.yaml @@ -11,6 +11,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 + with: + persist-credentials: false - uses: micnncim/action-label-syncer@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/functional-baremetal.yaml b/.github/workflows/functional-baremetal.yaml index 69455e91b0..8d92efd576 100644 --- a/.github/workflows/functional-baremetal.yaml +++ b/.github/workflows/functional-baremetal.yaml @@ -24,6 +24,8 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v6 + with: + persist-credentials: false - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-basic.yaml b/.github/workflows/functional-basic.yaml index 5f81afd1ac..4a4a38a31f 100644 --- a/.github/workflows/functional-basic.yaml +++ b/.github/workflows/functional-basic.yaml @@ -24,6 +24,8 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v6 + with: + persist-credentials: false - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-blockstorage.yaml b/.github/workflows/functional-blockstorage.yaml index 67ecfe9e61..3b540e3898 100644 --- a/.github/workflows/functional-blockstorage.yaml +++ b/.github/workflows/functional-blockstorage.yaml @@ -24,6 +24,8 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v6 + with: + persist-credentials: false - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-compute.yaml b/.github/workflows/functional-compute.yaml index b704ebd815..72e71d58c3 100644 --- a/.github/workflows/functional-compute.yaml +++ b/.github/workflows/functional-compute.yaml @@ -24,6 +24,8 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v6 + with: + persist-credentials: false - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-containerinfra.yaml b/.github/workflows/functional-containerinfra.yaml index 2128b5db1f..2ef91940f1 100644 --- a/.github/workflows/functional-containerinfra.yaml +++ b/.github/workflows/functional-containerinfra.yaml @@ -45,6 +45,8 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v6 + with: + persist-credentials: false - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-dns.yaml b/.github/workflows/functional-dns.yaml index ad0f78be29..6b5f0b06ca 100644 --- a/.github/workflows/functional-dns.yaml +++ b/.github/workflows/functional-dns.yaml @@ -30,6 +30,8 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v6 + with: + persist-credentials: false - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-fwaas_v2.yaml b/.github/workflows/functional-fwaas_v2.yaml index be6211ca78..34cd6a6007 100644 --- a/.github/workflows/functional-fwaas_v2.yaml +++ b/.github/workflows/functional-fwaas_v2.yaml @@ -28,6 +28,8 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v6 + with: + persist-credentials: false - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-identity.yaml b/.github/workflows/functional-identity.yaml index 2d3e65f6c1..e18ce5dddf 100644 --- a/.github/workflows/functional-identity.yaml +++ b/.github/workflows/functional-identity.yaml @@ -24,6 +24,8 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v6 + with: + persist-credentials: false - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-image.yaml b/.github/workflows/functional-image.yaml index 6a89bfdf73..4c1fd9f298 100644 --- a/.github/workflows/functional-image.yaml +++ b/.github/workflows/functional-image.yaml @@ -24,6 +24,8 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v6 + with: + persist-credentials: false - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-keymanager.yaml b/.github/workflows/functional-keymanager.yaml index 753fe0b841..d9a6d9c11d 100644 --- a/.github/workflows/functional-keymanager.yaml +++ b/.github/workflows/functional-keymanager.yaml @@ -36,6 +36,8 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v6 + with: + persist-credentials: false - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-loadbalancer.yaml b/.github/workflows/functional-loadbalancer.yaml index 8740cf21ce..7620d29ce8 100644 --- a/.github/workflows/functional-loadbalancer.yaml +++ b/.github/workflows/functional-loadbalancer.yaml @@ -35,6 +35,8 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v6 + with: + persist-credentials: false - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-messaging.yaml b/.github/workflows/functional-messaging.yaml index e4723ac922..7c1b7e476f 100644 --- a/.github/workflows/functional-messaging.yaml +++ b/.github/workflows/functional-messaging.yaml @@ -24,6 +24,8 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v6 + with: + persist-credentials: false - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-networking.yaml b/.github/workflows/functional-networking.yaml index e7bf14d7ee..778a1a8dd5 100644 --- a/.github/workflows/functional-networking.yaml +++ b/.github/workflows/functional-networking.yaml @@ -24,6 +24,8 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v6 + with: + persist-credentials: false - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-objectstorage.yaml b/.github/workflows/functional-objectstorage.yaml index e0c8ce599c..f18c4d28e7 100644 --- a/.github/workflows/functional-objectstorage.yaml +++ b/.github/workflows/functional-objectstorage.yaml @@ -24,6 +24,8 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v6 + with: + persist-credentials: false - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-orchestration.yaml b/.github/workflows/functional-orchestration.yaml index 545088574c..3551bbafad 100644 --- a/.github/workflows/functional-orchestration.yaml +++ b/.github/workflows/functional-orchestration.yaml @@ -24,6 +24,8 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v6 + with: + persist-credentials: false - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-placement.yaml b/.github/workflows/functional-placement.yaml index f65534d955..192b994d5f 100644 --- a/.github/workflows/functional-placement.yaml +++ b/.github/workflows/functional-placement.yaml @@ -24,6 +24,8 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v6 + with: + persist-credentials: false - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-sharedfilesystems.yaml b/.github/workflows/functional-sharedfilesystems.yaml index a723b9879b..3636005740 100644 --- a/.github/workflows/functional-sharedfilesystems.yaml +++ b/.github/workflows/functional-sharedfilesystems.yaml @@ -30,6 +30,8 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v6 + with: + persist-credentials: false - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/functional-workflow.yaml b/.github/workflows/functional-workflow.yaml index ee987992fb..7ab647caeb 100644 --- a/.github/workflows/functional-workflow.yaml +++ b/.github/workflows/functional-workflow.yaml @@ -27,6 +27,8 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v6 + with: + persist-credentials: false - name: Check changed files uses: ./.github/actions/file-filter diff --git a/.github/workflows/label-pr.yaml b/.github/workflows/label-pr.yaml index 423ea1fdc6..7cbc0e95bd 100644 --- a/.github/workflows/label-pr.yaml +++ b/.github/workflows/label-pr.yaml @@ -15,6 +15,7 @@ jobs: fetch-depth: 0 ref: ${{ github.event.pull_request.head.sha }} token: ${{ secrets.GITHUB_TOKEN }} + persist-credentials: false - name: Rebase the PR against origin/github.base_ref to ensure actual API compatibility run: | diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index f2e4fafa2b..84f2280f20 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -11,6 +11,8 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v6 + with: + persist-credentials: false - uses: actions/setup-go@v6 with: go-version-file: 'go.mod' diff --git a/.github/workflows/unit.yaml b/.github/workflows/unit.yaml index 01d4ea6697..a5858e7cb8 100644 --- a/.github/workflows/unit.yaml +++ b/.github/workflows/unit.yaml @@ -16,6 +16,8 @@ jobs: steps: - name: Checkout Gophercloud uses: actions/checkout@v6 + with: + persist-credentials: false - name: Setup Go uses: actions/setup-go@v6 with: From b3e4310a6e83e46e670e3ad30daab142a1d9a3a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Wed, 25 Mar 2026 11:31:38 +0100 Subject: [PATCH 327/429] ci: add explicit permissions to all workflow jobs Apply the principle of least privilege by adding explicit permissions blocks to every job that was relying on default (overly broad) permissions. Each job now declares only the permissions it needs. Reported by zizmor (excessive-permissions). --- .github/workflows/backport.yaml | 8 ++++++++ .github/workflows/check-pr-labels.yaml | 1 + .github/workflows/ensure-labels.yaml | 3 +++ .github/workflows/functional-baremetal.yaml | 2 ++ .github/workflows/functional-basic.yaml | 2 ++ .github/workflows/functional-blockstorage.yaml | 2 ++ .github/workflows/functional-compute.yaml | 2 ++ .github/workflows/functional-containerinfra.yaml | 2 ++ .github/workflows/functional-dns.yaml | 2 ++ .github/workflows/functional-fwaas_v2.yaml | 2 ++ .github/workflows/functional-identity.yaml | 2 ++ .github/workflows/functional-image.yaml | 2 ++ .github/workflows/functional-keymanager.yaml | 2 ++ .github/workflows/functional-loadbalancer.yaml | 2 ++ .github/workflows/functional-messaging.yaml | 2 ++ .github/workflows/functional-networking.yaml | 2 ++ .github/workflows/functional-objectstorage.yaml | 2 ++ .github/workflows/functional-orchestration.yaml | 2 ++ .github/workflows/functional-placement.yaml | 2 ++ .github/workflows/functional-sharedfilesystems.yaml | 2 ++ .github/workflows/functional-workflow.yaml | 2 ++ .github/workflows/label-pr.yaml | 4 ++++ 22 files changed, 52 insertions(+) diff --git a/.github/workflows/backport.yaml b/.github/workflows/backport.yaml index 04f06538ac..88704f66df 100644 --- a/.github/workflows/backport.yaml +++ b/.github/workflows/backport.yaml @@ -9,6 +9,10 @@ on: jobs: backport_v1: name: "Backport to v1" + permissions: + contents: read + issues: write + pull-requests: write # Only react to merged PRs for security reasons. # See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target. if: > @@ -70,6 +74,10 @@ jobs: backport_v2: name: "Backport to v2" + permissions: + contents: read + issues: write + pull-requests: write # Only react to merged PRs for security reasons. # See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target. if: > diff --git a/.github/workflows/check-pr-labels.yaml b/.github/workflows/check-pr-labels.yaml index 8d3cdde07b..2b30487abd 100644 --- a/.github/workflows/check-pr-labels.yaml +++ b/.github/workflows/check-pr-labels.yaml @@ -11,6 +11,7 @@ on: jobs: hold: + permissions: {} if: github.event.pull_request.merged == false runs-on: ubuntu-latest steps: diff --git a/.github/workflows/ensure-labels.yaml b/.github/workflows/ensure-labels.yaml index e881954b42..76f7e460f8 100644 --- a/.github/workflows/ensure-labels.yaml +++ b/.github/workflows/ensure-labels.yaml @@ -8,6 +8,9 @@ on: - .github/workflows/ensure-labels.yaml jobs: ensure: + permissions: + contents: read + issues: write runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 diff --git a/.github/workflows/functional-baremetal.yaml b/.github/workflows/functional-baremetal.yaml index 8d92efd576..2ab2e72976 100644 --- a/.github/workflows/functional-baremetal.yaml +++ b/.github/workflows/functional-baremetal.yaml @@ -6,6 +6,8 @@ on: - cron: '0 0 */3 * *' jobs: functional-baremetal: + permissions: + contents: read strategy: fail-fast: false matrix: diff --git a/.github/workflows/functional-basic.yaml b/.github/workflows/functional-basic.yaml index 4a4a38a31f..b80efe2da2 100644 --- a/.github/workflows/functional-basic.yaml +++ b/.github/workflows/functional-basic.yaml @@ -6,6 +6,8 @@ on: - cron: '0 0 */3 * *' jobs: functional-basic: + permissions: + contents: read strategy: fail-fast: false matrix: diff --git a/.github/workflows/functional-blockstorage.yaml b/.github/workflows/functional-blockstorage.yaml index 3b540e3898..bfde0f6d87 100644 --- a/.github/workflows/functional-blockstorage.yaml +++ b/.github/workflows/functional-blockstorage.yaml @@ -6,6 +6,8 @@ on: - cron: '0 0 */3 * *' jobs: functional-blockstorage: + permissions: + contents: read strategy: fail-fast: false matrix: diff --git a/.github/workflows/functional-compute.yaml b/.github/workflows/functional-compute.yaml index 72e71d58c3..87c967cf5d 100644 --- a/.github/workflows/functional-compute.yaml +++ b/.github/workflows/functional-compute.yaml @@ -6,6 +6,8 @@ on: - cron: '0 0 */3 * *' jobs: functional-compute: + permissions: + contents: read strategy: fail-fast: false matrix: diff --git a/.github/workflows/functional-containerinfra.yaml b/.github/workflows/functional-containerinfra.yaml index 2ef91940f1..743b6cf136 100644 --- a/.github/workflows/functional-containerinfra.yaml +++ b/.github/workflows/functional-containerinfra.yaml @@ -6,6 +6,8 @@ on: - cron: '0 0 */3 * *' jobs: functional-containerinfra: + permissions: + contents: read strategy: fail-fast: false matrix: diff --git a/.github/workflows/functional-dns.yaml b/.github/workflows/functional-dns.yaml index 6b5f0b06ca..795c5506ac 100644 --- a/.github/workflows/functional-dns.yaml +++ b/.github/workflows/functional-dns.yaml @@ -6,6 +6,8 @@ on: - cron: '0 0 */3 * *' jobs: functional-dns: + permissions: + contents: read strategy: fail-fast: false matrix: diff --git a/.github/workflows/functional-fwaas_v2.yaml b/.github/workflows/functional-fwaas_v2.yaml index 34cd6a6007..1fcefe8523 100644 --- a/.github/workflows/functional-fwaas_v2.yaml +++ b/.github/workflows/functional-fwaas_v2.yaml @@ -10,6 +10,8 @@ on: - cron: '0 0 */3 * *' jobs: functional-fwaas_v2: + permissions: + contents: read strategy: fail-fast: false matrix: diff --git a/.github/workflows/functional-identity.yaml b/.github/workflows/functional-identity.yaml index e18ce5dddf..ced561b8d9 100644 --- a/.github/workflows/functional-identity.yaml +++ b/.github/workflows/functional-identity.yaml @@ -6,6 +6,8 @@ on: - cron: '0 0 */3 * *' jobs: functional-identity: + permissions: + contents: read strategy: fail-fast: false matrix: diff --git a/.github/workflows/functional-image.yaml b/.github/workflows/functional-image.yaml index 4c1fd9f298..9cdcf5609a 100644 --- a/.github/workflows/functional-image.yaml +++ b/.github/workflows/functional-image.yaml @@ -6,6 +6,8 @@ on: - cron: '0 0 */3 * *' jobs: functional-image: + permissions: + contents: read strategy: fail-fast: false matrix: diff --git a/.github/workflows/functional-keymanager.yaml b/.github/workflows/functional-keymanager.yaml index d9a6d9c11d..4182c8c5d4 100644 --- a/.github/workflows/functional-keymanager.yaml +++ b/.github/workflows/functional-keymanager.yaml @@ -6,6 +6,8 @@ on: - cron: '0 0 */3 * *' jobs: functional-keymanager: + permissions: + contents: read strategy: fail-fast: false matrix: diff --git a/.github/workflows/functional-loadbalancer.yaml b/.github/workflows/functional-loadbalancer.yaml index 7620d29ce8..24d21112f3 100644 --- a/.github/workflows/functional-loadbalancer.yaml +++ b/.github/workflows/functional-loadbalancer.yaml @@ -6,6 +6,8 @@ on: - cron: '0 0 */3 * *' jobs: functional-loadbalancer: + permissions: + contents: read strategy: fail-fast: false matrix: diff --git a/.github/workflows/functional-messaging.yaml b/.github/workflows/functional-messaging.yaml index 7c1b7e476f..230d1d7018 100644 --- a/.github/workflows/functional-messaging.yaml +++ b/.github/workflows/functional-messaging.yaml @@ -6,6 +6,8 @@ on: - cron: '0 0 */3 * *' jobs: functional-messaging: + permissions: + contents: read strategy: fail-fast: false matrix: diff --git a/.github/workflows/functional-networking.yaml b/.github/workflows/functional-networking.yaml index 778a1a8dd5..120e6a13c2 100644 --- a/.github/workflows/functional-networking.yaml +++ b/.github/workflows/functional-networking.yaml @@ -6,6 +6,8 @@ on: - cron: '0 0 */3 * *' jobs: functional-networking: + permissions: + contents: read strategy: fail-fast: false matrix: diff --git a/.github/workflows/functional-objectstorage.yaml b/.github/workflows/functional-objectstorage.yaml index f18c4d28e7..a20e34d548 100644 --- a/.github/workflows/functional-objectstorage.yaml +++ b/.github/workflows/functional-objectstorage.yaml @@ -6,6 +6,8 @@ on: - cron: '0 0 */3 * *' jobs: functional-objectstorage: + permissions: + contents: read strategy: fail-fast: false matrix: diff --git a/.github/workflows/functional-orchestration.yaml b/.github/workflows/functional-orchestration.yaml index 3551bbafad..e735401d51 100644 --- a/.github/workflows/functional-orchestration.yaml +++ b/.github/workflows/functional-orchestration.yaml @@ -6,6 +6,8 @@ on: - cron: '0 0 */3 * *' jobs: functional-orchestration: + permissions: + contents: read strategy: fail-fast: false matrix: diff --git a/.github/workflows/functional-placement.yaml b/.github/workflows/functional-placement.yaml index 192b994d5f..cf1ca7d946 100644 --- a/.github/workflows/functional-placement.yaml +++ b/.github/workflows/functional-placement.yaml @@ -6,6 +6,8 @@ on: - cron: '0 0 */3 * *' jobs: functional-placement: + permissions: + contents: read strategy: fail-fast: false matrix: diff --git a/.github/workflows/functional-sharedfilesystems.yaml b/.github/workflows/functional-sharedfilesystems.yaml index 3636005740..a848d8a6dd 100644 --- a/.github/workflows/functional-sharedfilesystems.yaml +++ b/.github/workflows/functional-sharedfilesystems.yaml @@ -6,6 +6,8 @@ on: - cron: '0 0 */3 * *' jobs: functional-sharedfilesystems: + permissions: + contents: read strategy: fail-fast: false matrix: diff --git a/.github/workflows/functional-workflow.yaml b/.github/workflows/functional-workflow.yaml index 7ab647caeb..569e2d36bb 100644 --- a/.github/workflows/functional-workflow.yaml +++ b/.github/workflows/functional-workflow.yaml @@ -6,6 +6,8 @@ on: - cron: '0 0 */3 * *' jobs: functional-workflow: + permissions: + contents: read strategy: fail-fast: false matrix: diff --git a/.github/workflows/label-pr.yaml b/.github/workflows/label-pr.yaml index 7cbc0e95bd..e0fdb9ad17 100644 --- a/.github/workflows/label-pr.yaml +++ b/.github/workflows/label-pr.yaml @@ -8,6 +8,10 @@ on: jobs: semver: + permissions: + contents: read + issues: write + pull-requests: write runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 From 135f30d22527c40c3d32c30e7c731e6c9aa6a65d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Wed, 25 Mar 2026 11:32:10 +0100 Subject: [PATCH 328/429] ci: fix template injection vulnerabilities in workflow run blocks Replace ${{ env.* }} expressions in shell run blocks with native shell variable references ($VAR), and pass ${{ github.base_ref }} through an env variable instead of expanding it directly in a shell command. This prevents potential code injection through template expansion. Reported by zizmor (template-injection). --- .github/workflows/functional-baremetal.yaml | 2 +- .github/workflows/functional-basic.yaml | 2 +- .github/workflows/functional-blockstorage.yaml | 2 +- .github/workflows/functional-compute.yaml | 2 +- .github/workflows/functional-containerinfra.yaml | 2 +- .github/workflows/functional-dns.yaml | 2 +- .github/workflows/functional-fwaas_v2.yaml | 2 +- .github/workflows/functional-identity.yaml | 2 +- .github/workflows/functional-image.yaml | 2 +- .github/workflows/functional-keymanager.yaml | 2 +- .github/workflows/functional-loadbalancer.yaml | 2 +- .github/workflows/functional-messaging.yaml | 2 +- .github/workflows/functional-networking.yaml | 2 +- .github/workflows/functional-objectstorage.yaml | 2 +- .github/workflows/functional-orchestration.yaml | 2 +- .github/workflows/functional-placement.yaml | 2 +- .github/workflows/functional-sharedfilesystems.yaml | 2 +- .github/workflows/functional-workflow.yaml | 2 +- .github/workflows/label-pr.yaml | 3 ++- 19 files changed, 20 insertions(+), 19 deletions(-) diff --git a/.github/workflows/functional-baremetal.yaml b/.github/workflows/functional-baremetal.yaml index 2ab2e72976..d5bc6a0ab3 100644 --- a/.github/workflows/functional-baremetal.yaml +++ b/.github/workflows/functional-baremetal.yaml @@ -130,7 +130,7 @@ jobs: - name: Set job status run: | - if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + if [[ "$TESTS_SKIPPED" == "true" || "$TESTS_RUN" == "true" ]]; then echo "Job completed successfully (either ran tests or skipped appropriately)" exit 0 else diff --git a/.github/workflows/functional-basic.yaml b/.github/workflows/functional-basic.yaml index b80efe2da2..df679f399d 100644 --- a/.github/workflows/functional-basic.yaml +++ b/.github/workflows/functional-basic.yaml @@ -83,7 +83,7 @@ jobs: - name: Set job status run: | - if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + if [[ "$TESTS_SKIPPED" == "true" || "$TESTS_RUN" == "true" ]]; then echo "Job completed successfully (either ran tests or skipped appropriately)" exit 0 else diff --git a/.github/workflows/functional-blockstorage.yaml b/.github/workflows/functional-blockstorage.yaml index bfde0f6d87..7727e4c378 100644 --- a/.github/workflows/functional-blockstorage.yaml +++ b/.github/workflows/functional-blockstorage.yaml @@ -89,7 +89,7 @@ jobs: - name: Set job status run: | - if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + if [[ "$TESTS_SKIPPED" == "true" || "$TESTS_RUN" == "true" ]]; then echo "Job completed successfully (either ran tests or skipped appropriately)" exit 0 else diff --git a/.github/workflows/functional-compute.yaml b/.github/workflows/functional-compute.yaml index 87c967cf5d..a53169e81c 100644 --- a/.github/workflows/functional-compute.yaml +++ b/.github/workflows/functional-compute.yaml @@ -89,7 +89,7 @@ jobs: - name: Set job status run: | - if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + if [[ "$TESTS_SKIPPED" == "true" || "$TESTS_RUN" == "true" ]]; then echo "Job completed successfully (either ran tests or skipped appropriately)" exit 0 else diff --git a/.github/workflows/functional-containerinfra.yaml b/.github/workflows/functional-containerinfra.yaml index 743b6cf136..beaf44a1e2 100644 --- a/.github/workflows/functional-containerinfra.yaml +++ b/.github/workflows/functional-containerinfra.yaml @@ -116,7 +116,7 @@ jobs: - name: Set job status run: | - if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + if [[ "$TESTS_SKIPPED" == "true" || "$TESTS_RUN" == "true" ]]; then echo "Job completed successfully (either ran tests or skipped appropriately)" exit 0 else diff --git a/.github/workflows/functional-dns.yaml b/.github/workflows/functional-dns.yaml index 795c5506ac..21f5b732d3 100644 --- a/.github/workflows/functional-dns.yaml +++ b/.github/workflows/functional-dns.yaml @@ -97,7 +97,7 @@ jobs: - name: Set job status run: | - if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + if [[ "$TESTS_SKIPPED" == "true" || "$TESTS_RUN" == "true" ]]; then echo "Job completed successfully (either ran tests or skipped appropriately)" exit 0 else diff --git a/.github/workflows/functional-fwaas_v2.yaml b/.github/workflows/functional-fwaas_v2.yaml index 1fcefe8523..082225f7f3 100644 --- a/.github/workflows/functional-fwaas_v2.yaml +++ b/.github/workflows/functional-fwaas_v2.yaml @@ -112,7 +112,7 @@ jobs: - name: Set job status run: | - if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + if [[ "$TESTS_SKIPPED" == "true" || "$TESTS_RUN" == "true" ]]; then echo "Job completed successfully (either ran tests or skipped appropriately)" exit 0 else diff --git a/.github/workflows/functional-identity.yaml b/.github/workflows/functional-identity.yaml index ced561b8d9..53259796b1 100644 --- a/.github/workflows/functional-identity.yaml +++ b/.github/workflows/functional-identity.yaml @@ -87,7 +87,7 @@ jobs: - name: Set job status run: | - if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + if [[ "$TESTS_SKIPPED" == "true" || "$TESTS_RUN" == "true" ]]; then echo "Job completed successfully (either ran tests or skipped appropriately)" exit 0 else diff --git a/.github/workflows/functional-image.yaml b/.github/workflows/functional-image.yaml index 9cdcf5609a..95227639dd 100644 --- a/.github/workflows/functional-image.yaml +++ b/.github/workflows/functional-image.yaml @@ -87,7 +87,7 @@ jobs: - name: Set job status run: | - if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + if [[ "$TESTS_SKIPPED" == "true" || "$TESTS_RUN" == "true" ]]; then echo "Job completed successfully (either ran tests or skipped appropriately)" exit 0 else diff --git a/.github/workflows/functional-keymanager.yaml b/.github/workflows/functional-keymanager.yaml index 4182c8c5d4..7f06589fe1 100644 --- a/.github/workflows/functional-keymanager.yaml +++ b/.github/workflows/functional-keymanager.yaml @@ -103,7 +103,7 @@ jobs: - name: Set job status run: | - if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + if [[ "$TESTS_SKIPPED" == "true" || "$TESTS_RUN" == "true" ]]; then echo "Job completed successfully (either ran tests or skipped appropriately)" exit 0 else diff --git a/.github/workflows/functional-loadbalancer.yaml b/.github/workflows/functional-loadbalancer.yaml index 24d21112f3..50c7a3211b 100644 --- a/.github/workflows/functional-loadbalancer.yaml +++ b/.github/workflows/functional-loadbalancer.yaml @@ -103,7 +103,7 @@ jobs: - name: Set job status run: | - if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + if [[ "$TESTS_SKIPPED" == "true" || "$TESTS_RUN" == "true" ]]; then echo "Job completed successfully (either ran tests or skipped appropriately)" exit 0 else diff --git a/.github/workflows/functional-messaging.yaml b/.github/workflows/functional-messaging.yaml index 230d1d7018..669b0d1448 100644 --- a/.github/workflows/functional-messaging.yaml +++ b/.github/workflows/functional-messaging.yaml @@ -90,7 +90,7 @@ jobs: - name: Set job status run: | - if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + if [[ "$TESTS_SKIPPED" == "true" || "$TESTS_RUN" == "true" ]]; then echo "Job completed successfully (either ran tests or skipped appropriately)" exit 0 else diff --git a/.github/workflows/functional-networking.yaml b/.github/workflows/functional-networking.yaml index 120e6a13c2..ecc9961d38 100644 --- a/.github/workflows/functional-networking.yaml +++ b/.github/workflows/functional-networking.yaml @@ -107,7 +107,7 @@ jobs: - name: Set job status run: | - if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + if [[ "$TESTS_SKIPPED" == "true" || "$TESTS_RUN" == "true" ]]; then echo "Job completed successfully (either ran tests or skipped appropriately)" exit 0 else diff --git a/.github/workflows/functional-objectstorage.yaml b/.github/workflows/functional-objectstorage.yaml index a20e34d548..d2327a618c 100644 --- a/.github/workflows/functional-objectstorage.yaml +++ b/.github/workflows/functional-objectstorage.yaml @@ -93,7 +93,7 @@ jobs: - name: Set job status run: | - if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + if [[ "$TESTS_SKIPPED" == "true" || "$TESTS_RUN" == "true" ]]; then echo "Job completed successfully (either ran tests or skipped appropriately)" exit 0 else diff --git a/.github/workflows/functional-orchestration.yaml b/.github/workflows/functional-orchestration.yaml index e735401d51..0c6ff30d26 100644 --- a/.github/workflows/functional-orchestration.yaml +++ b/.github/workflows/functional-orchestration.yaml @@ -89,7 +89,7 @@ jobs: - name: Set job status run: | - if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + if [[ "$TESTS_SKIPPED" == "true" || "$TESTS_RUN" == "true" ]]; then echo "Job completed successfully (either ran tests or skipped appropriately)" exit 0 else diff --git a/.github/workflows/functional-placement.yaml b/.github/workflows/functional-placement.yaml index cf1ca7d946..0520b3e40e 100644 --- a/.github/workflows/functional-placement.yaml +++ b/.github/workflows/functional-placement.yaml @@ -87,7 +87,7 @@ jobs: - name: Set job status run: | - if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + if [[ "$TESTS_SKIPPED" == "true" || "$TESTS_RUN" == "true" ]]; then echo "Job completed successfully (either ran tests or skipped appropriately)" exit 0 else diff --git a/.github/workflows/functional-sharedfilesystems.yaml b/.github/workflows/functional-sharedfilesystems.yaml index a848d8a6dd..9847f1c2fd 100644 --- a/.github/workflows/functional-sharedfilesystems.yaml +++ b/.github/workflows/functional-sharedfilesystems.yaml @@ -111,7 +111,7 @@ jobs: - name: Set job status run: | - if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + if [[ "$TESTS_SKIPPED" == "true" || "$TESTS_RUN" == "true" ]]; then echo "Job completed successfully (either ran tests or skipped appropriately)" exit 0 else diff --git a/.github/workflows/functional-workflow.yaml b/.github/workflows/functional-workflow.yaml index 569e2d36bb..236c356bf5 100644 --- a/.github/workflows/functional-workflow.yaml +++ b/.github/workflows/functional-workflow.yaml @@ -92,7 +92,7 @@ jobs: - name: Set job status run: | - if [[ "${{ env.TESTS_SKIPPED }}" == "true" || "${{ env.TESTS_RUN }}" == "true" ]]; then + if [[ "$TESTS_SKIPPED" == "true" || "$TESTS_RUN" == "true" ]]; then echo "Job completed successfully (either ran tests or skipped appropriately)" exit 0 else diff --git a/.github/workflows/label-pr.yaml b/.github/workflows/label-pr.yaml index e0fdb9ad17..a15e54f7f0 100644 --- a/.github/workflows/label-pr.yaml +++ b/.github/workflows/label-pr.yaml @@ -25,9 +25,10 @@ jobs: run: | git config --global user.email "localrebase@gophercloud.io" git config --global user.name "Local rebase" - git rebase -i origin/${{ github.base_ref }} + git rebase -i origin/$BASE_REF env: GIT_SEQUENCE_EDITOR: '/usr/bin/true' + BASE_REF: ${{ github.base_ref }} - uses: actions/setup-go@v6 with: From 2981aebec8e0750e09ce32fcfbaa22bd5223176e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Wed, 25 Mar 2026 11:33:15 +0100 Subject: [PATCH 329/429] ci: pin all GitHub Actions to SHA hashes Pin all third-party action references to their full commit SHA to prevent supply-chain attacks through tag manipulation. A version comment is added after each SHA for maintainability. Reported by zizmor (unpinned-uses). --- .github/workflows/backport.yaml | 4 ++-- .github/workflows/codeql-analysis.yaml | 10 +++++----- .github/workflows/ensure-labels.yaml | 4 ++-- .github/workflows/functional-baremetal.yaml | 8 ++++---- .github/workflows/functional-basic.yaml | 8 ++++---- .github/workflows/functional-blockstorage.yaml | 8 ++++---- .github/workflows/functional-compute.yaml | 8 ++++---- .github/workflows/functional-containerinfra.yaml | 8 ++++---- .github/workflows/functional-dns.yaml | 8 ++++---- .github/workflows/functional-fwaas_v2.yaml | 8 ++++---- .github/workflows/functional-identity.yaml | 8 ++++---- .github/workflows/functional-image.yaml | 8 ++++---- .github/workflows/functional-keymanager.yaml | 8 ++++---- .github/workflows/functional-loadbalancer.yaml | 8 ++++---- .github/workflows/functional-messaging.yaml | 8 ++++---- .github/workflows/functional-networking.yaml | 8 ++++---- .github/workflows/functional-objectstorage.yaml | 8 ++++---- .github/workflows/functional-orchestration.yaml | 8 ++++---- .github/workflows/functional-placement.yaml | 8 ++++---- .github/workflows/functional-sharedfilesystems.yaml | 8 ++++---- .github/workflows/functional-workflow.yaml | 8 ++++---- .github/workflows/label-pr.yaml | 8 ++++---- .github/workflows/lint.yaml | 4 ++-- .github/workflows/unit.yaml | 8 ++++---- 24 files changed, 91 insertions(+), 91 deletions(-) diff --git a/.github/workflows/backport.yaml b/.github/workflows/backport.yaml index 88704f66df..2b403ddebf 100644 --- a/.github/workflows/backport.yaml +++ b/.github/workflows/backport.yaml @@ -38,7 +38,7 @@ jobs: if: > contains(github.event.pull_request.labels.*.name, 'semver:patch') || contains(github.event.label.name, 'semver:patch') - uses: kiegroup/git-backporting@baae3fe1e3c71bc6b1a2699b3bc1e153a19d5ac7 + uses: kiegroup/git-backporting@baae3fe1e3c71bc6b1a2699b3bc1e153a19d5ac7 # v4.8.7 with: target-branch: v1 pull-request: ${{ github.event.pull_request.url }} @@ -105,7 +105,7 @@ jobs: || contains(github.event.pull_request.labels.*.name, 'semver:minor') || contains(github.event.label.name, 'semver:patch') || contains(github.event.label.name, 'semver:minor') - uses: kiegroup/git-backporting@baae3fe1e3c71bc6b1a2699b3bc1e153a19d5ac7 + uses: kiegroup/git-backporting@baae3fe1e3c71bc6b1a2699b3bc1e153a19d5ac7 # v4.8.7 with: target-branch: v2 pull-request: ${{ github.event.pull_request.url }} diff --git a/.github/workflows/codeql-analysis.yaml b/.github/workflows/codeql-analysis.yaml index dabe73a738..3040b3cc41 100644 --- a/.github/workflows/codeql-analysis.yaml +++ b/.github/workflows/codeql-analysis.yaml @@ -18,23 +18,23 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false - name: Setup Go - uses: actions/setup-go@v6 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 with: go-version-file: 'go.mod' cache: true - name: Initialize CodeQL - uses: github/codeql-action/init@v4 + uses: github/codeql-action/init@38697555549f1db7851b81482ff19f1fa5c4fedc # v4 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@v4 + uses: github/codeql-action/autobuild@38697555549f1db7851b81482ff19f1fa5c4fedc # v4 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v4 + uses: github/codeql-action/analyze@38697555549f1db7851b81482ff19f1fa5c4fedc # v4 diff --git a/.github/workflows/ensure-labels.yaml b/.github/workflows/ensure-labels.yaml index 76f7e460f8..bb92db737b 100644 --- a/.github/workflows/ensure-labels.yaml +++ b/.github/workflows/ensure-labels.yaml @@ -13,10 +13,10 @@ jobs: issues: write runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false - - uses: micnncim/action-label-syncer@v1 + - uses: micnncim/action-label-syncer@3abd5ab72fda571e69fffd97bd4e0033dd5f495c # v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: diff --git a/.github/workflows/functional-baremetal.yaml b/.github/workflows/functional-baremetal.yaml index d5bc6a0ab3..88aa1ff597 100644 --- a/.github/workflows/functional-baremetal.yaml +++ b/.github/workflows/functional-baremetal.yaml @@ -25,7 +25,7 @@ jobs: name: Ironic on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false @@ -60,7 +60,7 @@ jobs: # This change however is suitable longer-term as it is not necessary for SDK testing. - name: Deploy devstack if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 + uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 # v0.19 with: branch: ${{ matrix.openstack_version }} conf_overrides: | @@ -101,7 +101,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v6 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 with: go-version-file: 'go.mod' cache: true @@ -123,7 +123,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 with: name: functional-baremetal-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-basic.yaml b/.github/workflows/functional-basic.yaml index df679f399d..9bd15f3c88 100644 --- a/.github/workflows/functional-basic.yaml +++ b/.github/workflows/functional-basic.yaml @@ -25,7 +25,7 @@ jobs: name: basic tests on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false @@ -48,14 +48,14 @@ jobs: - name: Deploy devstack if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 + uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 # v0.19 with: branch: ${{ matrix.openstack_version }} enabled_services: 's-account,s-container,s-object,s-proxy,openstack-cli-server' - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v6 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 with: go-version-file: 'go.mod' cache: true @@ -76,7 +76,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 with: name: functional-basic-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-blockstorage.yaml b/.github/workflows/functional-blockstorage.yaml index 7727e4c378..49e5c18b17 100644 --- a/.github/workflows/functional-blockstorage.yaml +++ b/.github/workflows/functional-blockstorage.yaml @@ -25,7 +25,7 @@ jobs: name: Cinder on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false @@ -52,7 +52,7 @@ jobs: - name: Deploy devstack if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 + uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 # v0.19 with: branch: ${{ matrix.openstack_version }} conf_overrides: | @@ -61,7 +61,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v6 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 with: go-version-file: 'go.mod' cache: true @@ -82,7 +82,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 with: name: functional-blockstorage-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-compute.yaml b/.github/workflows/functional-compute.yaml index a53169e81c..ff40c8a3e8 100644 --- a/.github/workflows/functional-compute.yaml +++ b/.github/workflows/functional-compute.yaml @@ -25,7 +25,7 @@ jobs: name: Nova on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false @@ -52,7 +52,7 @@ jobs: - name: Deploy devstack if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 + uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 # v0.19 with: branch: ${{ matrix.openstack_version }} conf_overrides: | @@ -61,7 +61,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v6 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 with: go-version-file: 'go.mod' cache: true @@ -82,7 +82,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 with: name: functional-compute-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-containerinfra.yaml b/.github/workflows/functional-containerinfra.yaml index beaf44a1e2..1c5e4b2317 100644 --- a/.github/workflows/functional-containerinfra.yaml +++ b/.github/workflows/functional-containerinfra.yaml @@ -46,7 +46,7 @@ jobs: name: Magnum on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false @@ -73,7 +73,7 @@ jobs: - name: Deploy devstack if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 + uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 # v0.19 with: branch: ${{ matrix.openstack_version }} conf_overrides: | @@ -88,7 +88,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v6 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 with: go-version-file: 'go.mod' cache: true @@ -109,7 +109,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 with: name: functional-containerinfra-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-dns.yaml b/.github/workflows/functional-dns.yaml index 21f5b732d3..57748e80a6 100644 --- a/.github/workflows/functional-dns.yaml +++ b/.github/workflows/functional-dns.yaml @@ -31,7 +31,7 @@ jobs: name: Designate on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false @@ -58,7 +58,7 @@ jobs: - name: Deploy devstack if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 + uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 # v0.19 with: branch: ${{ matrix.openstack_version }} conf_overrides: | @@ -69,7 +69,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v6 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 with: go-version-file: 'go.mod' cache: true @@ -90,7 +90,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 with: name: functional-dns-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-fwaas_v2.yaml b/.github/workflows/functional-fwaas_v2.yaml index 082225f7f3..c5d3a5157f 100644 --- a/.github/workflows/functional-fwaas_v2.yaml +++ b/.github/workflows/functional-fwaas_v2.yaml @@ -29,7 +29,7 @@ jobs: name: FWaaS_v2 on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false @@ -66,7 +66,7 @@ jobs: - name: Deploy devstack if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 + uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 # v0.19 with: branch: ${{ matrix.openstack_version }} conf_overrides: | @@ -84,7 +84,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v6 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 with: go-version-file: 'go.mod' cache: true @@ -105,7 +105,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 with: name: functional-fwaas_v2-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-identity.yaml b/.github/workflows/functional-identity.yaml index 53259796b1..af17bc082f 100644 --- a/.github/workflows/functional-identity.yaml +++ b/.github/workflows/functional-identity.yaml @@ -25,7 +25,7 @@ jobs: name: Keystone on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false @@ -52,14 +52,14 @@ jobs: - name: Deploy devstack if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 + uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 # v0.19 with: branch: ${{ matrix.openstack_version }} enabled_services: "openstack-cli-server" - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v6 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 with: go-version-file: 'go.mod' cache: true @@ -80,7 +80,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 with: name: functional-identity-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-image.yaml b/.github/workflows/functional-image.yaml index 95227639dd..cedc4625da 100644 --- a/.github/workflows/functional-image.yaml +++ b/.github/workflows/functional-image.yaml @@ -25,7 +25,7 @@ jobs: name: Glance on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false @@ -52,14 +52,14 @@ jobs: - name: Deploy devstack if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 + uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 # v0.19 with: branch: ${{ matrix.openstack_version }} enabled_services: "openstack-cli-server" - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v6 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 with: go-version-file: 'go.mod' cache: true @@ -80,7 +80,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 with: name: functional-image-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-keymanager.yaml b/.github/workflows/functional-keymanager.yaml index 7f06589fe1..8a87c286bf 100644 --- a/.github/workflows/functional-keymanager.yaml +++ b/.github/workflows/functional-keymanager.yaml @@ -37,7 +37,7 @@ jobs: name: Barbican on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false @@ -64,7 +64,7 @@ jobs: - name: Deploy devstack if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 + uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 # v0.19 with: branch: ${{ matrix.openstack_version }} conf_overrides: | @@ -75,7 +75,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v6 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 with: go-version-file: 'go.mod' cache: true @@ -96,7 +96,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 with: name: functional-keymanager-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-loadbalancer.yaml b/.github/workflows/functional-loadbalancer.yaml index 50c7a3211b..ded8fa188b 100644 --- a/.github/workflows/functional-loadbalancer.yaml +++ b/.github/workflows/functional-loadbalancer.yaml @@ -36,7 +36,7 @@ jobs: name: Octavia on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false @@ -63,7 +63,7 @@ jobs: - name: Deploy devstack if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 + uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 # v0.19 with: branch: ${{ matrix.openstack_version }} conf_overrides: | @@ -75,7 +75,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v6 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 with: go-version-file: 'go.mod' cache: true @@ -96,7 +96,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 with: name: functional-loadbalancer-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-messaging.yaml b/.github/workflows/functional-messaging.yaml index 669b0d1448..783359b4ed 100644 --- a/.github/workflows/functional-messaging.yaml +++ b/.github/workflows/functional-messaging.yaml @@ -25,7 +25,7 @@ jobs: name: Zaqar on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false @@ -52,7 +52,7 @@ jobs: - name: Deploy devstack if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 + uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 # v0.19 with: branch: ${{ matrix.openstack_version }} conf_overrides: | @@ -62,7 +62,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v6 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 with: go-version-file: 'go.mod' cache: true @@ -83,7 +83,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 with: name: functional-messaging-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-networking.yaml b/.github/workflows/functional-networking.yaml index ecc9961d38..c2332f921b 100644 --- a/.github/workflows/functional-networking.yaml +++ b/.github/workflows/functional-networking.yaml @@ -25,7 +25,7 @@ jobs: name: Neutron on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false @@ -62,7 +62,7 @@ jobs: - name: Deploy devstack if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 + uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 # v0.19 with: branch: ${{ matrix.openstack_version }} conf_overrides: | @@ -79,7 +79,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v6 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 with: go-version-file: 'go.mod' cache: true @@ -100,7 +100,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 with: name: functional-networking-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-objectstorage.yaml b/.github/workflows/functional-objectstorage.yaml index d2327a618c..a49c12f759 100644 --- a/.github/workflows/functional-objectstorage.yaml +++ b/.github/workflows/functional-objectstorage.yaml @@ -25,7 +25,7 @@ jobs: name: Swift on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false @@ -52,7 +52,7 @@ jobs: - name: Deploy devstack if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 + uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 # v0.19 with: branch: ${{ matrix.openstack_version }} conf_overrides: | @@ -65,7 +65,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v6 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 with: go-version-file: 'go.mod' cache: true @@ -86,7 +86,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 with: name: functional-objectstorage-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-orchestration.yaml b/.github/workflows/functional-orchestration.yaml index 0c6ff30d26..f805fa6ff0 100644 --- a/.github/workflows/functional-orchestration.yaml +++ b/.github/workflows/functional-orchestration.yaml @@ -25,7 +25,7 @@ jobs: name: Heat on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false @@ -52,7 +52,7 @@ jobs: - name: Deploy devstack if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 + uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 # v0.19 with: branch: ${{ matrix.openstack_version }} conf_overrides: | @@ -61,7 +61,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v6 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 with: go-version-file: 'go.mod' cache: true @@ -82,7 +82,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 with: name: functional-orchestration-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-placement.yaml b/.github/workflows/functional-placement.yaml index 0520b3e40e..b82ee3f74f 100644 --- a/.github/workflows/functional-placement.yaml +++ b/.github/workflows/functional-placement.yaml @@ -25,7 +25,7 @@ jobs: name: Placement on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false @@ -52,14 +52,14 @@ jobs: - name: Deploy devstack if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 + uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 # v0.19 with: branch: ${{ matrix.openstack_version }} enabled_services: "openstack-cli-server" - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v6 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 with: go-version-file: 'go.mod' cache: true @@ -80,7 +80,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 with: name: functional-placement-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-sharedfilesystems.yaml b/.github/workflows/functional-sharedfilesystems.yaml index 9847f1c2fd..7e6508d6f3 100644 --- a/.github/workflows/functional-sharedfilesystems.yaml +++ b/.github/workflows/functional-sharedfilesystems.yaml @@ -31,7 +31,7 @@ jobs: name: Manila on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false @@ -58,7 +58,7 @@ jobs: - name: Deploy devstack if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 + uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 # v0.19 with: branch: ${{ matrix.openstack_version }} conf_overrides: | @@ -83,7 +83,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v6 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 with: go-version-file: 'go.mod' cache: true @@ -104,7 +104,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 with: name: functional-sharedfilesystems-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-workflow.yaml b/.github/workflows/functional-workflow.yaml index 236c356bf5..8f29c75033 100644 --- a/.github/workflows/functional-workflow.yaml +++ b/.github/workflows/functional-workflow.yaml @@ -28,7 +28,7 @@ jobs: name: Mistral on Deploy OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false @@ -55,7 +55,7 @@ jobs: - name: Deploy devstack if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 + uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 # v0.19 with: branch: ${{ matrix.openstack_version }} conf_overrides: | @@ -64,7 +64,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@v6 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 with: go-version-file: 'go.mod' cache: true @@ -85,7 +85,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 with: name: functional-workflow-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/label-pr.yaml b/.github/workflows/label-pr.yaml index a15e54f7f0..f5f4256eb6 100644 --- a/.github/workflows/label-pr.yaml +++ b/.github/workflows/label-pr.yaml @@ -14,7 +14,7 @@ jobs: pull-requests: write runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: fetch-depth: 0 ref: ${{ github.event.pull_request.head.sha }} @@ -30,7 +30,7 @@ jobs: GIT_SEQUENCE_EDITOR: '/usr/bin/true' BASE_REF: ${{ github.base_ref }} - - uses: actions/setup-go@v6 + - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 with: go-version-file: 'go.mod' cache: true @@ -40,7 +40,7 @@ jobs: # if semver=major, this will return RC=1, so let's ignore the failure so label # can be set later. We check for actual errors in the next step. continue-on-error: true - uses: joelanford/go-apidiff@60c4206be8f84348ebda2a3e0c3ac9cb54b8f685 + uses: joelanford/go-apidiff@60c4206be8f84348ebda2a3e0c3ac9cb54b8f685 # v0.8.3 # go-apidiff returns RC=1 when semver=major, which makes the workflow to return # a failure. Instead let's just return a failure if go-apidiff failed to run. @@ -116,4 +116,4 @@ jobs: pull-requests: write runs-on: ubuntu-latest steps: - - uses: actions/labeler@v6 + - uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6 diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 84f2280f20..b019a83b55 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -10,10 +10,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Gophercloud - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false - - uses: actions/setup-go@v6 + - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/unit.yaml b/.github/workflows/unit.yaml index a5858e7cb8..c938fd0a8c 100644 --- a/.github/workflows/unit.yaml +++ b/.github/workflows/unit.yaml @@ -15,11 +15,11 @@ jobs: fail-fast: false steps: - name: Checkout Gophercloud - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false - name: Setup Go - uses: actions/setup-go@v6 + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 with: go-version-file: 'go.mod' cache: true @@ -34,7 +34,7 @@ jobs: make unit make coverage - name: Check coverage - uses: coverallsapp/github-action@v2 + uses: coverallsapp/github-action@5cbfd81b66ca5d10c19b062c04de0199c215fb6e # v2 with: file: cover.out parallel: true @@ -46,6 +46,6 @@ jobs: runs-on: ubuntu-latest steps: - name: Store coverage results - uses: coverallsapp/github-action@v2 + uses: coverallsapp/github-action@5cbfd81b66ca5d10c19b062c04de0199c215fb6e # v2 with: parallel-finished: true From e1da83f5af8c00d5668f3cb84a6946f8a9fde0bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Wed, 25 Mar 2026 11:33:45 +0100 Subject: [PATCH 330/429] ci: suppress secrets-outside-env warnings in backport workflow Add inline zizmor ignore comments for secrets used outside a dedicated GitHub Environment. Fixing this properly requires external repository configuration (creating a GitHub Environment) which cannot be done from code alone. Reported by zizmor (secrets-outside-env). --- .github/workflows/backport.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/backport.yaml b/.github/workflows/backport.yaml index 2b403ddebf..1c4b6fe420 100644 --- a/.github/workflows/backport.yaml +++ b/.github/workflows/backport.yaml @@ -31,8 +31,8 @@ jobs: id: generate_token uses: getsentry/action-github-app-token@a0061014b82a6a5d6aeeb3b824aced47e3c3a7ef with: - app_id: ${{ secrets.BACKPORT_APP_ID }} - private_key: ${{ secrets.BACKPORT_APP_PRIVATE_KEY }} + app_id: ${{ secrets.BACKPORT_APP_ID }} # zizmor: ignore[secrets-outside-env] + private_key: ${{ secrets.BACKPORT_APP_PRIVATE_KEY }} # zizmor: ignore[secrets-outside-env] - name: Backporting if: > @@ -96,8 +96,8 @@ jobs: id: generate_token uses: getsentry/action-github-app-token@a0061014b82a6a5d6aeeb3b824aced47e3c3a7ef with: - app_id: ${{ secrets.BACKPORT_APP_ID }} - private_key: ${{ secrets.BACKPORT_APP_PRIVATE_KEY }} + app_id: ${{ secrets.BACKPORT_APP_ID }} # zizmor: ignore[secrets-outside-env] + private_key: ${{ secrets.BACKPORT_APP_PRIVATE_KEY }} # zizmor: ignore[secrets-outside-env] - name: Backporting if: > From 4a163e8fb494ef301400a68329a2459abfa782a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Wed, 25 Mar 2026 14:10:47 +0100 Subject: [PATCH 331/429] ci: replace pull_request_target with pull_request in check-pr-labels The hold job has zero permissions, no secrets access, and no code checkout, so the privileged pull_request_target trigger is unnecessary. The merge_group trigger remains as the tamper-proof gate for the merge queue. Reported by zizmor (dangerous-triggers). --- .github/workflows/check-pr-labels.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-pr-labels.yaml b/.github/workflows/check-pr-labels.yaml index 2b30487abd..a81d2b223a 100644 --- a/.github/workflows/check-pr-labels.yaml +++ b/.github/workflows/check-pr-labels.yaml @@ -1,7 +1,7 @@ name: Ready on: merge_group: - pull_request_target: + pull_request: types: - labeled - opened From 01de474dd045d77a885c6f59437796271ac89b8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Wed, 25 Mar 2026 14:11:00 +0100 Subject: [PATCH 332/429] ci: suppress dangerous-triggers warning in backport workflow The pull_request_target trigger is required here to access secrets for the backport bot token. The workflow is safe: it only runs on merged PRs (github.event.pull_request.merged guard), does not checkout or execute any PR code, and uses a dedicated GitHub App token for creating backport PRs. Reported by zizmor (dangerous-triggers). --- .github/workflows/backport.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/backport.yaml b/.github/workflows/backport.yaml index 1c4b6fe420..b23910b5d4 100644 --- a/.github/workflows/backport.yaml +++ b/.github/workflows/backport.yaml @@ -1,7 +1,9 @@ name: Pull Request backporting on: - pull_request_target: + # Safe: only runs on merged PRs, does not checkout PR code, and + # needs secrets to generate the backport bot token. + pull_request_target: # zizmor: ignore[dangerous-triggers] types: - closed - labeled From 031765f054ea80a5b06f815aff5692dc722e0806 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Wed, 25 Mar 2026 14:19:41 +0100 Subject: [PATCH 333/429] ci: split semver analysis from label-pr to fix dangerous-triggers Extract the semver analysis (checkout, rebase, go-apidiff) into a new semver.yaml workflow triggered by pull_request, which runs in the unprivileged fork context. The privileged labeling logic stays in label-pr.yaml as a new semver-label job triggered by workflow_run on completion of the analysis. PR number and base ref are resolved via the GitHub API from the workflow_run head SHA. The edits job (actions/labeler) remains on pull_request_target with an event_name guard. Both triggers are suppressed with inline comments: neither job checks out or executes PR code. Reported by zizmor (dangerous-triggers). --- .github/workflows/label-pr.yaml | 115 +++++++++++++++++--------------- .github/workflows/semver.yaml | 62 +++++++++++++++++ 2 files changed, 124 insertions(+), 53 deletions(-) create mode 100644 .github/workflows/semver.yaml diff --git a/.github/workflows/label-pr.yaml b/.github/workflows/label-pr.yaml index f5f4256eb6..d30c28ae99 100644 --- a/.github/workflows/label-pr.yaml +++ b/.github/workflows/label-pr.yaml @@ -1,55 +1,76 @@ name: Label PR on: - pull_request_target: + # Safe: the edits job does not checkout or execute any PR code. + # It only runs the pinned actions/labeler action which reads event + # metadata and the base branch .github/labeler.yml configuration. + pull_request_target: # zizmor: ignore[dangerous-triggers] types: - opened - synchronize - reopened + # Safe: the semver-label job never checks out or executes PR code. + # It only reads a data artifact produced by the unprivileged + # "Semver analysis" workflow and uses the GitHub API to apply labels. + workflow_run: # zizmor: ignore[dangerous-triggers] + workflows: ["Semver analysis"] + types: + - completed + +permissions: {} jobs: - semver: + semver-label: + if: github.event_name == 'workflow_run' + runs-on: ubuntu-latest permissions: - contents: read + actions: read issues: write pull-requests: write - runs-on: ubuntu-latest steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - with: - fetch-depth: 0 - ref: ${{ github.event.pull_request.head.sha }} - token: ${{ secrets.GITHUB_TOKEN }} - persist-credentials: false + - name: Get PR number and base ref + id: pr + run: | + PR_DATA=$(gh api "repos/$REPO/commits/$HEAD_SHA/pulls" --jq '.[0] | {number, base_ref: .base.ref}') + PR_NUMBER=$(echo "$PR_DATA" | jq -r '.number') + BASE_REF=$(echo "$PR_DATA" | jq -r '.base_ref') + if [ -z "$PR_NUMBER" ] || [ "$PR_NUMBER" = "null" ]; then + echo "Could not determine PR number" >&2 + exit 1 + fi + echo "number=$PR_NUMBER" >> "$GITHUB_OUTPUT" + echo "base-ref=$BASE_REF" >> "$GITHUB_OUTPUT" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO: ${{ github.repository }} + HEAD_SHA: ${{ github.event.workflow_run.head_sha }} - - name: Rebase the PR against origin/github.base_ref to ensure actual API compatibility + - name: Report failure + if: github.event.workflow_run.conclusion == 'failure' run: | - git config --global user.email "localrebase@gophercloud.io" - git config --global user.name "Local rebase" - git rebase -i origin/$BASE_REF + gh pr edit "$NUMBER" --remove-label "semver:major,semver:minor,semver:patch,backport-v2,backport-v1" + gh issue comment "$NUMBER" --body "$BODY" env: - GIT_SEQUENCE_EDITOR: '/usr/bin/true' - BASE_REF: ${{ github.base_ref }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_REPO: ${{ github.repository }} + NUMBER: ${{ steps.pr.outputs.number }} + BODY: > + Failed to assess the semver bump. See [logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.event.workflow_run.id }}) for details. - - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + - name: Download semver results + if: github.event.workflow_run.conclusion == 'success' + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 with: - go-version-file: 'go.mod' - cache: true + name: semver-results + run-id: ${{ github.event.workflow_run.id }} + github-token: ${{ secrets.GITHUB_TOKEN }} - - name: Checking Go API Compatibility - id: go-apidiff - # if semver=major, this will return RC=1, so let's ignore the failure so label - # can be set later. We check for actual errors in the next step. - continue-on-error: true - uses: joelanford/go-apidiff@60c4206be8f84348ebda2a3e0c3ac9cb54b8f685 # v0.8.3 - - # go-apidiff returns RC=1 when semver=major, which makes the workflow to return - # a failure. Instead let's just return a failure if go-apidiff failed to run. - - name: Return an error if Go API Compatibility couldn't be verified - if: steps.go-apidiff.outcome != 'success' && steps.go-apidiff.outputs.semver-type != 'major' - run: exit 1 + - name: Read semver type + if: github.event.workflow_run.conclusion == 'success' + id: semver + run: echo "type=$(cat semver-type)" >> "$GITHUB_OUTPUT" - name: Add label semver:patch - if: steps.go-apidiff.outputs.semver-type == 'patch' + if: github.event.workflow_run.conclusion == 'success' && steps.semver.outputs.type == 'patch' run: | LABELS="semver:patch" REMOVE_LABELS="semver:major,semver:minor" @@ -65,11 +86,11 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} - NUMBER: ${{ github.event.pull_request.number }} - BASE_REF: ${{ github.base_ref }} + NUMBER: ${{ steps.pr.outputs.number }} + BASE_REF: ${{ steps.pr.outputs.base-ref }} - name: Add label semver:minor - if: steps.go-apidiff.outputs.semver-type == 'minor' + if: github.event.workflow_run.conclusion == 'success' && steps.semver.outputs.type == 'minor' run: | LABELS="semver:minor" REMOVE_LABELS="semver:major,semver:patch" @@ -86,34 +107,22 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} - NUMBER: ${{ github.event.pull_request.number }} - BASE_REF: ${{ github.base_ref }} + NUMBER: ${{ steps.pr.outputs.number }} + BASE_REF: ${{ steps.pr.outputs.base-ref }} - name: Add label semver:major - if: steps.go-apidiff.outputs.semver-type == 'major' + if: github.event.workflow_run.conclusion == 'success' && steps.semver.outputs.type == 'major' run: gh pr edit "$NUMBER" --add-label "semver:major" --remove-label "semver:minor,semver:patch,backport-v2,backport-v1" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} - NUMBER: ${{ github.event.pull_request.number }} - - - name: Report failure - if: failure() - run: | - gh pr edit "$NUMBER" --remove-label "semver:major,semver:minor,semver:patch,backport-v2,backport-v1" - gh issue comment "$NUMBER" --body "$BODY" - exit 1 - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_REPO: ${{ github.repository }} - NUMBER: ${{ github.event.pull_request.number }} - BODY: > - Failed to assess the semver bump. See [logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details. + NUMBER: ${{ steps.pr.outputs.number }} edits: + if: github.event_name == 'pull_request_target' + runs-on: ubuntu-latest permissions: contents: read pull-requests: write - runs-on: ubuntu-latest steps: - uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6 diff --git a/.github/workflows/semver.yaml b/.github/workflows/semver.yaml new file mode 100644 index 0000000000..5d54e77299 --- /dev/null +++ b/.github/workflows/semver.yaml @@ -0,0 +1,62 @@ +name: Semver analysis +on: + pull_request: + types: + - opened + - synchronize + - reopened + +permissions: + contents: read + +jobs: + analyze: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha }} + persist-credentials: false + + - name: Rebase the PR against base ref to ensure actual API compatibility + run: | + git config --global user.email "localrebase@gophercloud.io" + git config --global user.name "Local rebase" + git rebase -i origin/$BASE_REF + env: + GIT_SEQUENCE_EDITOR: '/usr/bin/true' + BASE_REF: ${{ github.base_ref }} + + - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + with: + go-version-file: 'go.mod' + cache: true + + - name: Checking Go API Compatibility + id: go-apidiff + # if semver=major, this will return RC=1, so let's ignore the failure so label + # can be set later. We check for actual errors in the next step. + continue-on-error: true + uses: joelanford/go-apidiff@60c4206be8f84348ebda2a3e0c3ac9cb54b8f685 # v0.8.3 + + # go-apidiff returns RC=1 when semver=major, which makes the workflow to return + # a failure. Instead let's just return a failure if go-apidiff failed to run. + - name: Return an error if Go API Compatibility couldn't be verified + if: steps.go-apidiff.outcome != 'success' && steps.go-apidiff.outputs.semver-type != 'major' + run: exit 1 + + - name: Save semver result + if: always() + run: | + mkdir -p semver-results + echo "$SEMVER_TYPE" > semver-results/semver-type + env: + SEMVER_TYPE: ${{ steps.go-apidiff.outputs.semver-type }} + + - name: Upload semver results + if: always() + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 + with: + name: semver-results + path: semver-results/ From 54ebc3629b6c3e0952014f3c3b4c37ee9022aab0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Wed, 25 Mar 2026 14:40:16 +0100 Subject: [PATCH 334/429] ci: add zizmor security scanner for GitHub Actions workflows Run zizmor on pushes to master and pull requests that modify workflow files. Results are uploaded as SARIF to GitHub's security-events API for code scanning integration. --- .github/workflows/zizmor.yaml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .github/workflows/zizmor.yaml diff --git a/.github/workflows/zizmor.yaml b/.github/workflows/zizmor.yaml new file mode 100644 index 0000000000..494a54ed80 --- /dev/null +++ b/.github/workflows/zizmor.yaml @@ -0,0 +1,28 @@ +name: zizmor + +on: + push: + branches: + - master + paths: + - '.github/workflows/**' + pull_request: + paths: + - '.github/workflows/**' + +permissions: {} + +jobs: + zizmor: + runs-on: ubuntu-latest + permissions: + security-events: write + contents: read + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Run zizmor + uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2 From 69bf30cc747dc374970feb9b794118b143bf96e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Thu, 26 Mar 2026 08:05:21 +0100 Subject: [PATCH 335/429] Fix TestCreateTempURL flaky test by removing hardcoded port dependency SetupPersistentPortHTTP used t.Errorf on bind failure, which didn't stop execution and caused a nil pointer panic on server.Start(). Changed to t.Fatalf to fail cleanly. Replaced SetupPersistentPortHTTP with SetupHTTP in objectstorage temp URL tests since the HMAC signature only covers the path, not the host:port. This eliminates the flaky port-already-in-use failures in CI. Fixes #3661. --- .../objectstorage/v1/objects/testing/requests_test.go | 8 +++----- testhelper/http_responses.go | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/openstack/objectstorage/v1/objects/testing/requests_test.go b/openstack/objectstorage/v1/objects/testing/requests_test.go index 004b798ba7..b49cf63a7f 100644 --- a/openstack/objectstorage/v1/objects/testing/requests_test.go +++ b/openstack/objectstorage/v1/objects/testing/requests_test.go @@ -93,8 +93,7 @@ func TestContainerNames(t *testing.T) { th.CheckErr(t, res.Err, &tc.expectedError) }) t.Run("createTempURL", func(t *testing.T) { - port := 33201 - fakeServer := th.SetupPersistentPortHTTP(t, port) + fakeServer := th.SetupHTTP() defer fakeServer.Teardown() // Handle fetching of secret key inside of CreateTempURL @@ -503,8 +502,7 @@ func TestObjectCreateParamsWithSeek(t *testing.T) { } func TestCreateTempURL(t *testing.T) { - port := 33200 - fakeServer := th.SetupPersistentPortHTTP(t, port) + fakeServer := th.SetupHTTP() defer fakeServer.Teardown() // Handle fetching of secret key inside of CreateTempURL @@ -522,7 +520,7 @@ func TestCreateTempURL(t *testing.T) { sig := "89be454a9c7e2e9f3f50a8441815e0b5801cba5b" expiry := "1593565980" - expectedURL := fmt.Sprintf("http://127.0.0.1:%v/v1/testContainer/testObject%%2FtestFile.txt?temp_url_sig=%v&temp_url_expires=%v", port, sig, expiry) + expectedURL := fmt.Sprintf("%sv1/testContainer/testObject%%2FtestFile.txt?temp_url_sig=%v&temp_url_expires=%v", fakeServer.Endpoint(), sig, expiry) th.AssertNoErr(t, err) th.AssertEquals(t, expectedURL, tempURL) diff --git a/testhelper/http_responses.go b/testhelper/http_responses.go index f57645e441..d0034a5a7b 100644 --- a/testhelper/http_responses.go +++ b/testhelper/http_responses.go @@ -50,7 +50,7 @@ func SetupPersistentPortHTTP(t *testing.T, port int) FakeServer { server := httptest.NewUnstartedServer(mux) l, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port)) if err != nil { - t.Errorf("Failed to listen to 127.0.0.1:%d: %s", port, err) + t.Fatalf("Failed to listen to 127.0.0.1:%d: %s", port, err) } server.Listener = l server.Start() From 2254df15bd217b958c0cb019d1933b11c2b41c36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Thu, 26 Mar 2026 08:29:43 +0100 Subject: [PATCH 336/429] Replace t.Errorf with th.AssertNoErr to prevent nil pointer panics in tests Several tests used t.Errorf after fallible operations, which logs the error but doesn't stop execution. This caused nil pointer dereferences when subsequent code accessed the result. Replace with th.AssertNoErr which calls t.Fatal internally, stopping the test immediately on error. --- .../sharedfilesystems/v2/replicas_test.go | 8 ++------ .../v2/securityservices_test.go | 13 ++++-------- .../v2/sharenetworks_test.go | 12 +++-------- .../sharedfilesystems/v2/shares_test.go | 20 +++++-------------- .../sharedfilesystems/v2/snapshots_test.go | 12 +++-------- .../v3/tokens/testing/requests_test.go | 16 ++++----------- 6 files changed, 21 insertions(+), 60 deletions(-) diff --git a/internal/acceptance/openstack/sharedfilesystems/v2/replicas_test.go b/internal/acceptance/openstack/sharedfilesystems/v2/replicas_test.go index 8432afeb77..e662781360 100644 --- a/internal/acceptance/openstack/sharedfilesystems/v2/replicas_test.go +++ b/internal/acceptance/openstack/sharedfilesystems/v2/replicas_test.go @@ -181,15 +181,11 @@ func TestReplicaExportLocations(t *testing.T) { } exportLocations, err = replicas.ListExportLocations(context.TODO(), client, activeReplicaID).Extract() - if err != nil { - t.Errorf("Unable to list replica export locations: %v", err) - } + th.AssertNoErr(t, err) tools.PrintResource(t, exportLocations) exportLocation, err := replicas.GetExportLocation(context.TODO(), client, activeReplicaID, exportLocations[0].ID).Extract() - if err != nil { - t.Errorf("Unable to get replica export location: %v", err) - } + th.AssertNoErr(t, err) tools.PrintResource(t, exportLocation) // unset CreatedAt and UpdatedAt exportLocation.CreatedAt = time.Time{} diff --git a/internal/acceptance/openstack/sharedfilesystems/v2/securityservices_test.go b/internal/acceptance/openstack/sharedfilesystems/v2/securityservices_test.go index a149a83324..abbb0b557c 100644 --- a/internal/acceptance/openstack/sharedfilesystems/v2/securityservices_test.go +++ b/internal/acceptance/openstack/sharedfilesystems/v2/securityservices_test.go @@ -9,6 +9,7 @@ import ( "github.com/gophercloud/gophercloud/v2/internal/acceptance/clients" "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" "github.com/gophercloud/gophercloud/v2/openstack/sharedfilesystems/v2/securityservices" + th "github.com/gophercloud/gophercloud/v2/testhelper" ) func TestSecurityServiceCreateDelete(t *testing.T) { @@ -23,9 +24,7 @@ func TestSecurityServiceCreateDelete(t *testing.T) { } newSecurityService, err := securityservices.Get(context.TODO(), client, securityService.ID).Extract() - if err != nil { - t.Errorf("Unable to retrieve the security service: %v", err) - } + th.AssertNoErr(t, err) if newSecurityService.Name != securityService.Name { t.Fatalf("Security service name was expeted to be: %s", securityService.Name) @@ -125,14 +124,10 @@ func TestSecurityServiceUpdate(t *testing.T) { } _, err = securityservices.Update(context.TODO(), client, securityService.ID, options).Extract() - if err != nil { - t.Errorf("Unable to update the security service: %v", err) - } + th.AssertNoErr(t, err) newSecurityService, err := securityservices.Get(context.TODO(), client, securityService.ID).Extract() - if err != nil { - t.Errorf("Unable to retrieve the security service: %v", err) - } + th.AssertNoErr(t, err) if newSecurityService.Name != name { t.Fatalf("Security service name was expeted to be: %s", name) diff --git a/internal/acceptance/openstack/sharedfilesystems/v2/sharenetworks_test.go b/internal/acceptance/openstack/sharedfilesystems/v2/sharenetworks_test.go index c6a9bf1530..c75c07a26b 100644 --- a/internal/acceptance/openstack/sharedfilesystems/v2/sharenetworks_test.go +++ b/internal/acceptance/openstack/sharedfilesystems/v2/sharenetworks_test.go @@ -25,9 +25,7 @@ func TestShareNetworkCreateDestroy(t *testing.T) { } newShareNetwork, err := sharenetworks.Get(context.TODO(), client, shareNetwork.ID).Extract() - if err != nil { - t.Errorf("Unable to retrieve shareNetwork: %v", err) - } + th.AssertNoErr(t, err) if newShareNetwork.Name != shareNetwork.Name { t.Fatalf("Share network name was expeted to be: %s", shareNetwork.Name) @@ -56,9 +54,7 @@ func TestShareNetworkUpdate(t *testing.T) { } expectedShareNetwork, err := sharenetworks.Get(context.TODO(), client, shareNetwork.ID).Extract() - if err != nil { - t.Errorf("Unable to retrieve shareNetwork: %v", err) - } + th.AssertNoErr(t, err) name := "NewName" description := "" @@ -76,9 +72,7 @@ func TestShareNetworkUpdate(t *testing.T) { } updatedShareNetwork, err := sharenetworks.Get(context.TODO(), client, shareNetwork.ID).Extract() - if err != nil { - t.Errorf("Unable to retrieve shareNetwork: %v", err) - } + th.AssertNoErr(t, err) // Update time has to be set in order to get the assert equal to pass expectedShareNetwork.UpdatedAt = updatedShareNetwork.UpdatedAt diff --git a/internal/acceptance/openstack/sharedfilesystems/v2/shares_test.go b/internal/acceptance/openstack/sharedfilesystems/v2/shares_test.go index 3d8bb0d32e..7247aa8984 100644 --- a/internal/acceptance/openstack/sharedfilesystems/v2/shares_test.go +++ b/internal/acceptance/openstack/sharedfilesystems/v2/shares_test.go @@ -53,15 +53,11 @@ func TestShareExportLocations(t *testing.T) { client.Microversion = "2.9" exportLocations, err := shares.ListExportLocations(context.TODO(), client, share.ID).Extract() - if err != nil { - t.Errorf("Unable to list share export locations: %v", err) - } + th.AssertNoErr(t, err) tools.PrintResource(t, exportLocations) exportLocation, err := shares.GetExportLocation(context.TODO(), client, share.ID, exportLocations[0].ID).Extract() - if err != nil { - t.Errorf("Unable to get share export location: %v", err) - } + th.AssertNoErr(t, err) tools.PrintResource(t, exportLocation) th.AssertEquals(t, exportLocations[0], *exportLocation) } @@ -80,9 +76,7 @@ func TestShareUpdate(t *testing.T) { defer DeleteShare(t, client, share) expectedShare, err := shares.Get(context.TODO(), client, share.ID).Extract() - if err != nil { - t.Errorf("Unable to retrieve share: %v", err) - } + th.AssertNoErr(t, err) name := "NewName" description := "" @@ -98,14 +92,10 @@ func TestShareUpdate(t *testing.T) { expectedShare.IsPublic = iFalse _, err = shares.Update(context.TODO(), client, share.ID, options).Extract() - if err != nil { - t.Errorf("Unable to update share: %v", err) - } + th.AssertNoErr(t, err) updatedShare, err := shares.Get(context.TODO(), client, share.ID).Extract() - if err != nil { - t.Errorf("Unable to retrieve share: %v", err) - } + th.AssertNoErr(t, err) // Update time has to be set in order to get the assert equal to pass expectedShare.UpdatedAt = updatedShare.UpdatedAt diff --git a/internal/acceptance/openstack/sharedfilesystems/v2/snapshots_test.go b/internal/acceptance/openstack/sharedfilesystems/v2/snapshots_test.go index 46b7c6d488..3c997d3c49 100644 --- a/internal/acceptance/openstack/sharedfilesystems/v2/snapshots_test.go +++ b/internal/acceptance/openstack/sharedfilesystems/v2/snapshots_test.go @@ -65,9 +65,7 @@ func TestSnapshotUpdate(t *testing.T) { defer DeleteSnapshot(t, client, snapshot) expectedSnapshot, err := snapshots.Get(context.TODO(), client, snapshot.ID).Extract() - if err != nil { - t.Errorf("Unable to retrieve snapshot: %v", err) - } + th.AssertNoErr(t, err) name := "NewName" description := "" @@ -80,14 +78,10 @@ func TestSnapshotUpdate(t *testing.T) { expectedSnapshot.Description = description _, err = snapshots.Update(context.TODO(), client, snapshot.ID, options).Extract() - if err != nil { - t.Errorf("Unable to update snapshot: %v", err) - } + th.AssertNoErr(t, err) updatedSnapshot, err := snapshots.Get(context.TODO(), client, snapshot.ID).Extract() - if err != nil { - t.Errorf("Unable to retrieve snapshot: %v", err) - } + th.AssertNoErr(t, err) tools.PrintResource(t, snapshot) diff --git a/openstack/identity/v3/tokens/testing/requests_test.go b/openstack/identity/v3/tokens/testing/requests_test.go index c8c5d49805..d099ef11ca 100644 --- a/openstack/identity/v3/tokens/testing/requests_test.go +++ b/openstack/identity/v3/tokens/testing/requests_test.go @@ -383,18 +383,14 @@ func TestCreateUserIDPasswordTrustID(t *testing.T) { rsp := tokens.Create(context.TODO(), client.ServiceClient(fakeServer), &ao) token, err := rsp.Extract() - if err != nil { - t.Errorf("Create returned an error: %v", err) - } + th.AssertNoErr(t, err) expectedToken := &tokens.Token{ ExpiresAt: time.Date(2024, 02, 28, 12, 10, 39, 0, time.UTC), } th.AssertDeepEquals(t, expectedToken, token) trust, err := rsp.ExtractTrust() - if err != nil { - t.Errorf("ExtractTrust returned an error: %v", err) - } + th.AssertNoErr(t, err) expectedTrust := &tokens.Trust{ ID: "95946f9eef864fdc993079d8fe3e5747", Impersonation: false, @@ -676,9 +672,7 @@ func TestGetRequest(t *testing.T) { }) token, err := tokens.Get(context.TODO(), &client, "abcdef12345", nil).Extract() - if err != nil { - t.Errorf("Info returned an error: %v", err) - } + th.AssertNoErr(t, err) expected, _ := time.Parse(time.UnixDate, "Fri Aug 29 13:10:01 UTC 2014") if token.ExpiresAt != expected { @@ -795,9 +789,7 @@ func TestGetRequestWithAccessRules(t *testing.T) { AccessRulesVersion: "1", } token, err := tokens.Get(context.TODO(), &client, "abcdef12345", getOpts).Extract() - if err != nil { - t.Errorf("Get returned an error: %v", err) - } + th.AssertNoErr(t, err) expected, _ := time.Parse(time.UnixDate, "Fri Aug 29 13:10:01 UTC 2014") if token.ExpiresAt != expected { From 7850e65b94d1ed4c4a57313bf297d5ac5d5e56ef Mon Sep 17 00:00:00 2001 From: Dominik Danelski Date: Wed, 25 Mar 2026 13:18:31 +0100 Subject: [PATCH 337/429] Implement READ operations on Placement traits Related: #526 API reference: https://docs.openstack.org/api-ref/placement/#traits Code reference: https://github.com/openstack/placement/blob/stable/2025.1/placement/handlers/trait.py#L108-L124 https://github.com/openstack/placement/blob/stable/2025.1/placement/handlers/trait.py#L152-L178 Signed-off-by: Dominik Danelski --- .../openstack/placement/v1/traits_test.go | 98 ++++++++++++++++ openstack/placement/v1/traits/doc.go | 42 +++++++ openstack/placement/v1/traits/requests.go | 60 ++++++++++ openstack/placement/v1/traits/results.go | 38 ++++++ openstack/placement/v1/traits/testing/doc.go | 2 + .../v1/traits/testing/fixtures_test.go | 108 ++++++++++++++++++ .../v1/traits/testing/requests_test.go | 101 ++++++++++++++++ openstack/placement/v1/traits/urls.go | 15 +++ 8 files changed, 464 insertions(+) create mode 100644 internal/acceptance/openstack/placement/v1/traits_test.go create mode 100644 openstack/placement/v1/traits/doc.go create mode 100644 openstack/placement/v1/traits/requests.go create mode 100644 openstack/placement/v1/traits/results.go create mode 100644 openstack/placement/v1/traits/testing/doc.go create mode 100644 openstack/placement/v1/traits/testing/fixtures_test.go create mode 100644 openstack/placement/v1/traits/testing/requests_test.go create mode 100644 openstack/placement/v1/traits/urls.go diff --git a/internal/acceptance/openstack/placement/v1/traits_test.go b/internal/acceptance/openstack/placement/v1/traits_test.go new file mode 100644 index 0000000000..3099da80df --- /dev/null +++ b/internal/acceptance/openstack/placement/v1/traits_test.go @@ -0,0 +1,98 @@ +//go:build acceptance || placement || traits + +package v1 + +import ( + "context" + "net/http" + "slices" + "strings" + "testing" + + "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/internal/acceptance/clients" + "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/traits" + th "github.com/gophercloud/gophercloud/v2/testhelper" +) + +func TestTraitsList(t *testing.T) { + // The Traits API requires microversion 1.6 or later + clients.SkipRelease(t, "stable/mitaka") + clients.SkipRelease(t, "stable/newton") + clients.SkipRelease(t, "stable/ocata") + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + client.Microversion = "1.6" + + allPages, err := traits.List(client, traits.ListOpts{}).AllPages(context.TODO()) + th.AssertNoErr(t, err) + + allTraits, err := traits.ExtractTraits(allPages) + th.AssertNoErr(t, err) + + // Ensure COMPUTE_NODE is in the list + // os-traits never removes traits, so this should always pass + th.AssertEquals(t, true, slices.Contains(allTraits, "COMPUTE_NODE")) +} + +func TestTraitGet(t *testing.T) { + // The Traits API requires microversion 1.6 or later + clients.SkipRelease(t, "stable/mitaka") + clients.SkipRelease(t, "stable/newton") + clients.SkipRelease(t, "stable/ocata") + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + client.Microversion = "1.6" + + // Verify that Get confirms the existence of the COMPUTE_NODE trait + // os-traits never removes traits, so this should always pass + err = traits.Get(context.TODO(), client, "COMPUTE_NODE").ExtractErr() + th.AssertNoErr(t, err) +} + +func TestTraitGetNegative(t *testing.T) { + // The Traits API requires microversion 1.6 or later + clients.SkipRelease(t, "stable/mitaka") + clients.SkipRelease(t, "stable/newton") + clients.SkipRelease(t, "stable/ocata") + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + client.Microversion = "1.6" + + // Verify that Get returns an error for a non-existent trait + err = traits.Get(context.TODO(), client, "CUSTOM_NON_EXISTENT_TRAIT").ExtractErr() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) +} + +func TestTraitsListFiltering(t *testing.T) { + // The Traits API requires microversion 1.6 or later + clients.SkipRelease(t, "stable/mitaka") + clients.SkipRelease(t, "stable/newton") + clients.SkipRelease(t, "stable/ocata") + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + client.Microversion = "1.6" + + // os-traits never removes traits, so this should always pass + listOpts := traits.ListOpts{ + Name: "startswith:HW_", + } + + allPages, err := traits.List(client, listOpts).AllPages(context.TODO()) + th.AssertNoErr(t, err) + + filteredTraits, err := traits.ExtractTraits(allPages) + th.AssertNoErr(t, err) + + for _, trait := range filteredTraits { + th.AssertEquals(t, true, strings.HasPrefix(trait, "HW_")) + } +} diff --git a/openstack/placement/v1/traits/doc.go b/openstack/placement/v1/traits/doc.go new file mode 100644 index 0000000000..e11afc158e --- /dev/null +++ b/openstack/placement/v1/traits/doc.go @@ -0,0 +1,42 @@ +/* +Package traits lists traits from the OpenStack Placement service. + +Traits API requests are available starting from microversion 1.6. + +Example to list traits + + placementClient.Microversion = "1.6" + + allPages, err := traits.List(placementClient, traits.ListOpts{}).AllPages(context.TODO()) + if err != nil { + panic(err) + } + + allTraits, err := traits.ExtractTraits(allPages) + if err != nil { + panic(err) + } + + for _, t := range allTraits { + fmt.Println(t) + } + +Example to check if a trait exists + + placementClient.Microversion = "1.6" + + traitName := "CUSTOM_HW_FPGA_CLASS1" + err := traits.Get(context.TODO(), placementClient, traitName).ExtractErr() + if err != nil { + if gophercloud.ResponseCodeIs(err, http.StatusNotFound) { + // 404 Not Found - The trait does not exist + fmt.Println("Trait does not exist.") + } else { + // Another error occurred + panic(err) + } + } else { + fmt.Println("Trait exists!") + } +*/ +package traits diff --git a/openstack/placement/v1/traits/requests.go b/openstack/placement/v1/traits/requests.go new file mode 100644 index 0000000000..82fd8a0dbb --- /dev/null +++ b/openstack/placement/v1/traits/requests.go @@ -0,0 +1,60 @@ +package traits + +import ( + "context" + + "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/pagination" +) + +// ListOptsBuilder allows extensions to add additional parameters to +// the List request. +type ListOptsBuilder interface { + ToTraitListQuery() (string, error) +} + +// ListOpts allows the filtering of traits. Filtering is achieved by passing in struct +// field values that map to the trait attributes you want to see returned. +type ListOpts struct { + // Name is a string used to filter traits by name. + // It supports startswith operator to filter the traits whose name begins with + // a specific prefix, e.g. name=startswith:CUSTOM + // in operator filters the traits whose name is in the specified list, + // e.g. name=in:HW_CPU_X86_AVX,HW_CPU_X86_SSE,HW_CPU_X86_INVALID_FEATURE + Name string `q:"name"` + + // Associated is a boolean used to filter traits by whether they are associated with + // at least one resource provider. + Associated *bool `q:"associated"` +} + +// ToTraitListQuery formats a ListOpts into a query string. +func (opts ListOpts) ToTraitListQuery() (string, error) { + q, err := gophercloud.BuildQueryString(opts) + return q.String(), err +} + +// List retrieves a list of traits. +func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { + url := listURL(client) + + if opts != nil { + query, err := opts.ToTraitListQuery() + if err != nil { + return pagination.Pager{Err: err} + } + url += query + } + return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page { + return TraitsPage{pagination.SinglePageBase(r)} + }) +} + +// Get confirms the existence of a trait. +func Get(ctx context.Context, client *gophercloud.ServiceClient, traitName string) (r GetResult) { + resp, err := client.Get(ctx, getURL(client, traitName), nil, &gophercloud.RequestOpts{ + OkCodes: []int{204}, + }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} diff --git a/openstack/placement/v1/traits/results.go b/openstack/placement/v1/traits/results.go new file mode 100644 index 0000000000..5e638cf226 --- /dev/null +++ b/openstack/placement/v1/traits/results.go @@ -0,0 +1,38 @@ +package traits + +import ( + "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/pagination" +) + +// GetResult is the response from a Get operation. Call its ExtractErr to +// determine if the request succeeded or failed. +type GetResult struct { + gophercloud.ErrResult +} + +// TraitsPage contains a single page of all traits from a List call. +type TraitsPage struct { + pagination.SinglePageBase +} + +// IsEmpty satisfies the IsEmpty method of the Page interface. It returns true +// if a List contains no results. +func (r TraitsPage) IsEmpty() (bool, error) { + if r.StatusCode == 204 { + return true, nil + } + + traits, err := ExtractTraits(r) + return len(traits) == 0, err +} + +// ExtractTraits takes a List result and extracts the collection of traits +// returned by the API. +func ExtractTraits(p pagination.Page) ([]string, error) { + var s struct { + Traits []string `json:"traits"` + } + err := (p.(TraitsPage)).ExtractInto(&s) + return s.Traits, err +} diff --git a/openstack/placement/v1/traits/testing/doc.go b/openstack/placement/v1/traits/testing/doc.go new file mode 100644 index 0000000000..3231ffdf0e --- /dev/null +++ b/openstack/placement/v1/traits/testing/doc.go @@ -0,0 +1,2 @@ +// placement traits +package testing diff --git a/openstack/placement/v1/traits/testing/fixtures_test.go b/openstack/placement/v1/traits/testing/fixtures_test.go new file mode 100644 index 0000000000..6c37649d18 --- /dev/null +++ b/openstack/placement/v1/traits/testing/fixtures_test.go @@ -0,0 +1,108 @@ +package testing + +import ( + "fmt" + "net/http" + "testing" + + th "github.com/gophercloud/gophercloud/v2/testhelper" + "github.com/gophercloud/gophercloud/v2/testhelper/client" +) + +const PresentTrait = "CUSTOM_HW_FPGA_CLASS1" +const AbsentTrait = "NON_EXISTENT_TRAIT" + +const TraitsListResultAll = ` +{ + "traits": [ + "CUSTOM_HW_FPGA_CLASS1", + "CUSTOM_HW_FPGA_CLASS2", + "HW_CPU_X86_AVX" + ] +}` + +const TraitsListFilteredCustomResult = ` +{ + "traits": [ + "CUSTOM_HW_FPGA_CLASS1", + "CUSTOM_HW_FPGA_CLASS2" + ] +}` + +const TraitsListFilteredAssociatedResult = TraitsListResultAll + +var ExpectedTraitsListResultAll = []string{ + "CUSTOM_HW_FPGA_CLASS1", + "CUSTOM_HW_FPGA_CLASS2", + "HW_CPU_X86_AVX", +} + +var ExpectedTraitsListFilteredNameResult = []string{ + "CUSTOM_HW_FPGA_CLASS1", + "CUSTOM_HW_FPGA_CLASS2", +} + +var ExpectedTraitsListFilteredAssociatedResult = ExpectedTraitsListResultAll + +func HandleListTraitsAll(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/traits", + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, TraitsListResultAll) + }) +} + +func HandleListTraitsFilteredName(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/traits", + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + th.TestFormValues(t, r, map[string]string{"name": "startswith:CUSTOM"}) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, TraitsListFilteredCustomResult) + }) +} + +func HandleListTraitsFilteredAssociated(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/traits", + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + th.TestFormValues(t, r, map[string]string{"associated": "true"}) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, TraitsListFilteredAssociatedResult) + }) +} + +func HandleGetTraitSuccess(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/traits/"+PresentTrait, + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.WriteHeader(http.StatusNoContent) + }) +} + +func HandleGetTraitNotFound(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/traits/"+AbsentTrait, + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.WriteHeader(http.StatusNotFound) + }) +} diff --git a/openstack/placement/v1/traits/testing/requests_test.go b/openstack/placement/v1/traits/testing/requests_test.go new file mode 100644 index 0000000000..39642afb91 --- /dev/null +++ b/openstack/placement/v1/traits/testing/requests_test.go @@ -0,0 +1,101 @@ +package testing + +import ( + "context" + "net/http" + "testing" + + "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/traits" + + "github.com/gophercloud/gophercloud/v2/pagination" + th "github.com/gophercloud/gophercloud/v2/testhelper" + "github.com/gophercloud/gophercloud/v2/testhelper/client" +) + +func TestListTraitsAll(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleListTraitsAll(t, fakeServer) + + count := 0 + err := traits.List(client.ServiceClient(fakeServer), traits.ListOpts{}).EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) { + count++ + + actual, err := traits.ExtractTraits(page) + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedTraitsListResultAll, actual) + + return true, nil + }) + + th.AssertNoErr(t, err) + + th.AssertEquals(t, 1, count) +} + +func TestListTraitsFilteredName(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleListTraitsFilteredName(t, fakeServer) + + count := 0 + err := traits.List(client.ServiceClient(fakeServer), traits.ListOpts{Name: "startswith:CUSTOM"}).EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) { + count++ + + actual, err := traits.ExtractTraits(page) + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedTraitsListFilteredNameResult, actual) + + return true, nil + }) + + th.AssertNoErr(t, err) + + th.AssertEquals(t, 1, count) +} + +func TestListTraitsFilteredAssociated(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleListTraitsFilteredAssociated(t, fakeServer) + + count := 0 + associated := true + err := traits.List(client.ServiceClient(fakeServer), traits.ListOpts{Associated: &associated}).EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) { + count++ + + actual, err := traits.ExtractTraits(page) + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedTraitsListFilteredAssociatedResult, actual) + + return true, nil + }) + + th.AssertNoErr(t, err) + + th.AssertEquals(t, 1, count) +} + +func TestGetTraitSuccess(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleGetTraitSuccess(t, fakeServer) + + err := traits.Get(context.TODO(), client.ServiceClient(fakeServer), PresentTrait).ExtractErr() + th.AssertNoErr(t, err) +} + +func TestGetTraitNotFound(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleGetTraitNotFound(t, fakeServer) + + err := traits.Get(context.TODO(), client.ServiceClient(fakeServer), AbsentTrait).ExtractErr() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) +} diff --git a/openstack/placement/v1/traits/urls.go b/openstack/placement/v1/traits/urls.go new file mode 100644 index 0000000000..a6ea7757a1 --- /dev/null +++ b/openstack/placement/v1/traits/urls.go @@ -0,0 +1,15 @@ +package traits + +import "github.com/gophercloud/gophercloud/v2" + +const ( + apiName = "traits" +) + +func listURL(client *gophercloud.ServiceClient) string { + return client.ServiceURL(apiName) +} + +func getURL(client *gophercloud.ServiceClient, traitName string) string { + return client.ServiceURL(apiName, traitName) +} From 3be82725db07df15ec7c435e9fa7cbfe133917b6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Mar 2026 09:03:30 +0000 Subject: [PATCH 338/429] build(deps): bump kiegroup/git-backporting from 4.8.7 to 4.9.1 Bumps [kiegroup/git-backporting](https://github.com/kiegroup/git-backporting) from 4.8.7 to 4.9.1. - [Release notes](https://github.com/kiegroup/git-backporting/releases) - [Changelog](https://github.com/kiegroup/git-backporting/blob/main/CHANGELOG.md) - [Commits](https://github.com/kiegroup/git-backporting/compare/baae3fe1e3c71bc6b1a2699b3bc1e153a19d5ac7...08da0b07ef2330d189f6074ec8db736b3aa9f465) --- updated-dependencies: - dependency-name: kiegroup/git-backporting dependency-version: 4.9.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/backport.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/backport.yaml b/.github/workflows/backport.yaml index b23910b5d4..ba02bce85b 100644 --- a/.github/workflows/backport.yaml +++ b/.github/workflows/backport.yaml @@ -40,7 +40,7 @@ jobs: if: > contains(github.event.pull_request.labels.*.name, 'semver:patch') || contains(github.event.label.name, 'semver:patch') - uses: kiegroup/git-backporting@baae3fe1e3c71bc6b1a2699b3bc1e153a19d5ac7 # v4.8.7 + uses: kiegroup/git-backporting@08da0b07ef2330d189f6074ec8db736b3aa9f465 # v4.9.1 with: target-branch: v1 pull-request: ${{ github.event.pull_request.url }} @@ -107,7 +107,7 @@ jobs: || contains(github.event.pull_request.labels.*.name, 'semver:minor') || contains(github.event.label.name, 'semver:patch') || contains(github.event.label.name, 'semver:minor') - uses: kiegroup/git-backporting@baae3fe1e3c71bc6b1a2699b3bc1e153a19d5ac7 # v4.8.7 + uses: kiegroup/git-backporting@08da0b07ef2330d189f6074ec8db736b3aa9f465 # v4.9.1 with: target-branch: v2 pull-request: ${{ github.event.pull_request.url }} From 6f68ef2199ad229d1320e0b9d8035bfc0e092d7a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Mar 2026 09:03:58 +0000 Subject: [PATCH 339/429] build(deps): bump actions/upload-artifact from 6.0.0 to 7.0.0 Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6.0.0 to 7.0.0. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/b7c566a772e6b6bfb58ed0dc250532a479d7789f...bbbca2ddaa5d8feaa63e36b76fdaad77386f024f) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/functional-baremetal.yaml | 2 +- .github/workflows/functional-basic.yaml | 2 +- .github/workflows/functional-blockstorage.yaml | 2 +- .github/workflows/functional-compute.yaml | 2 +- .github/workflows/functional-containerinfra.yaml | 2 +- .github/workflows/functional-dns.yaml | 2 +- .github/workflows/functional-fwaas_v2.yaml | 2 +- .github/workflows/functional-identity.yaml | 2 +- .github/workflows/functional-image.yaml | 2 +- .github/workflows/functional-keymanager.yaml | 2 +- .github/workflows/functional-loadbalancer.yaml | 2 +- .github/workflows/functional-messaging.yaml | 2 +- .github/workflows/functional-networking.yaml | 2 +- .github/workflows/functional-objectstorage.yaml | 2 +- .github/workflows/functional-orchestration.yaml | 2 +- .github/workflows/functional-placement.yaml | 2 +- .github/workflows/functional-sharedfilesystems.yaml | 2 +- .github/workflows/functional-workflow.yaml | 2 +- .github/workflows/semver.yaml | 2 +- 19 files changed, 19 insertions(+), 19 deletions(-) diff --git a/.github/workflows/functional-baremetal.yaml b/.github/workflows/functional-baremetal.yaml index 88aa1ff597..7021620482 100644 --- a/.github/workflows/functional-baremetal.yaml +++ b/.github/workflows/functional-baremetal.yaml @@ -123,7 +123,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: functional-baremetal-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-basic.yaml b/.github/workflows/functional-basic.yaml index 9bd15f3c88..8964c0b550 100644 --- a/.github/workflows/functional-basic.yaml +++ b/.github/workflows/functional-basic.yaml @@ -76,7 +76,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: functional-basic-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-blockstorage.yaml b/.github/workflows/functional-blockstorage.yaml index 49e5c18b17..4d981062d1 100644 --- a/.github/workflows/functional-blockstorage.yaml +++ b/.github/workflows/functional-blockstorage.yaml @@ -82,7 +82,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: functional-blockstorage-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-compute.yaml b/.github/workflows/functional-compute.yaml index ff40c8a3e8..46c7cb41bd 100644 --- a/.github/workflows/functional-compute.yaml +++ b/.github/workflows/functional-compute.yaml @@ -82,7 +82,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: functional-compute-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-containerinfra.yaml b/.github/workflows/functional-containerinfra.yaml index 1c5e4b2317..294624b0f1 100644 --- a/.github/workflows/functional-containerinfra.yaml +++ b/.github/workflows/functional-containerinfra.yaml @@ -109,7 +109,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: functional-containerinfra-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-dns.yaml b/.github/workflows/functional-dns.yaml index 57748e80a6..7abe11855f 100644 --- a/.github/workflows/functional-dns.yaml +++ b/.github/workflows/functional-dns.yaml @@ -90,7 +90,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: functional-dns-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-fwaas_v2.yaml b/.github/workflows/functional-fwaas_v2.yaml index c5d3a5157f..b3f381756e 100644 --- a/.github/workflows/functional-fwaas_v2.yaml +++ b/.github/workflows/functional-fwaas_v2.yaml @@ -105,7 +105,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: functional-fwaas_v2-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-identity.yaml b/.github/workflows/functional-identity.yaml index af17bc082f..7bdbf7ab9c 100644 --- a/.github/workflows/functional-identity.yaml +++ b/.github/workflows/functional-identity.yaml @@ -80,7 +80,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: functional-identity-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-image.yaml b/.github/workflows/functional-image.yaml index cedc4625da..8254a7d0c8 100644 --- a/.github/workflows/functional-image.yaml +++ b/.github/workflows/functional-image.yaml @@ -80,7 +80,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: functional-image-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-keymanager.yaml b/.github/workflows/functional-keymanager.yaml index 8a87c286bf..fee5e6603b 100644 --- a/.github/workflows/functional-keymanager.yaml +++ b/.github/workflows/functional-keymanager.yaml @@ -96,7 +96,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: functional-keymanager-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-loadbalancer.yaml b/.github/workflows/functional-loadbalancer.yaml index ded8fa188b..3886f48146 100644 --- a/.github/workflows/functional-loadbalancer.yaml +++ b/.github/workflows/functional-loadbalancer.yaml @@ -96,7 +96,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: functional-loadbalancer-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-messaging.yaml b/.github/workflows/functional-messaging.yaml index 783359b4ed..fc7de2d4ad 100644 --- a/.github/workflows/functional-messaging.yaml +++ b/.github/workflows/functional-messaging.yaml @@ -83,7 +83,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: functional-messaging-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-networking.yaml b/.github/workflows/functional-networking.yaml index c2332f921b..1ff2ce14fc 100644 --- a/.github/workflows/functional-networking.yaml +++ b/.github/workflows/functional-networking.yaml @@ -100,7 +100,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: functional-networking-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-objectstorage.yaml b/.github/workflows/functional-objectstorage.yaml index a49c12f759..04f1a6d56a 100644 --- a/.github/workflows/functional-objectstorage.yaml +++ b/.github/workflows/functional-objectstorage.yaml @@ -86,7 +86,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: functional-objectstorage-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-orchestration.yaml b/.github/workflows/functional-orchestration.yaml index f805fa6ff0..0eaf8885a6 100644 --- a/.github/workflows/functional-orchestration.yaml +++ b/.github/workflows/functional-orchestration.yaml @@ -82,7 +82,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: functional-orchestration-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-placement.yaml b/.github/workflows/functional-placement.yaml index b82ee3f74f..99eb3cca0b 100644 --- a/.github/workflows/functional-placement.yaml +++ b/.github/workflows/functional-placement.yaml @@ -80,7 +80,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: functional-placement-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-sharedfilesystems.yaml b/.github/workflows/functional-sharedfilesystems.yaml index 7e6508d6f3..426111ed36 100644 --- a/.github/workflows/functional-sharedfilesystems.yaml +++ b/.github/workflows/functional-sharedfilesystems.yaml @@ -104,7 +104,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: functional-sharedfilesystems-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-workflow.yaml b/.github/workflows/functional-workflow.yaml index 8f29c75033..dc4030ba77 100644 --- a/.github/workflows/functional-workflow.yaml +++ b/.github/workflows/functional-workflow.yaml @@ -85,7 +85,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: functional-workflow-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/semver.yaml b/.github/workflows/semver.yaml index 5d54e77299..9da00aa88e 100644 --- a/.github/workflows/semver.yaml +++ b/.github/workflows/semver.yaml @@ -56,7 +56,7 @@ jobs: - name: Upload semver results if: always() - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: semver-results path: semver-results/ From 869c802c4dca9c84152cb7d5b8cdc0673cafb3c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Thu, 26 Mar 2026 09:40:45 +0100 Subject: [PATCH 340/429] ci: pass PR number and base ref through artifact instead of API The commits/:sha/pulls API endpoint does not return results for fork PRs because the commit does not exist in the base repository. Instead, include the PR number and base ref in the artifact uploaded by the semver analysis workflow, where they are always available from the pull_request event context. This fixes up commit 031765f054ea80a5b06f815aff5692dc722e0806. --- .github/workflows/label-pr.yaml | 52 ++++++++++++--------------------- .github/workflows/semver.yaml | 4 +++ 2 files changed, 22 insertions(+), 34 deletions(-) diff --git a/.github/workflows/label-pr.yaml b/.github/workflows/label-pr.yaml index d30c28ae99..c876bf6625 100644 --- a/.github/workflows/label-pr.yaml +++ b/.github/workflows/label-pr.yaml @@ -27,22 +27,19 @@ jobs: issues: write pull-requests: write steps: - - name: Get PR number and base ref - id: pr + - name: Download semver results + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 + with: + name: semver-results + run-id: ${{ github.event.workflow_run.id }} + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Read semver results + id: semver run: | - PR_DATA=$(gh api "repos/$REPO/commits/$HEAD_SHA/pulls" --jq '.[0] | {number, base_ref: .base.ref}') - PR_NUMBER=$(echo "$PR_DATA" | jq -r '.number') - BASE_REF=$(echo "$PR_DATA" | jq -r '.base_ref') - if [ -z "$PR_NUMBER" ] || [ "$PR_NUMBER" = "null" ]; then - echo "Could not determine PR number" >&2 - exit 1 - fi - echo "number=$PR_NUMBER" >> "$GITHUB_OUTPUT" - echo "base-ref=$BASE_REF" >> "$GITHUB_OUTPUT" - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - REPO: ${{ github.repository }} - HEAD_SHA: ${{ github.event.workflow_run.head_sha }} + echo "type=$(cat semver-type)" >> "$GITHUB_OUTPUT" + echo "pr-number=$(cat pr-number)" >> "$GITHUB_OUTPUT" + echo "base-ref=$(cat base-ref)" >> "$GITHUB_OUTPUT" - name: Report failure if: github.event.workflow_run.conclusion == 'failure' @@ -52,23 +49,10 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} - NUMBER: ${{ steps.pr.outputs.number }} + NUMBER: ${{ steps.semver.outputs.pr-number }} BODY: > Failed to assess the semver bump. See [logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.event.workflow_run.id }}) for details. - - name: Download semver results - if: github.event.workflow_run.conclusion == 'success' - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 - with: - name: semver-results - run-id: ${{ github.event.workflow_run.id }} - github-token: ${{ secrets.GITHUB_TOKEN }} - - - name: Read semver type - if: github.event.workflow_run.conclusion == 'success' - id: semver - run: echo "type=$(cat semver-type)" >> "$GITHUB_OUTPUT" - - name: Add label semver:patch if: github.event.workflow_run.conclusion == 'success' && steps.semver.outputs.type == 'patch' run: | @@ -86,8 +70,8 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} - NUMBER: ${{ steps.pr.outputs.number }} - BASE_REF: ${{ steps.pr.outputs.base-ref }} + NUMBER: ${{ steps.semver.outputs.pr-number }} + BASE_REF: ${{ steps.semver.outputs.base-ref }} - name: Add label semver:minor if: github.event.workflow_run.conclusion == 'success' && steps.semver.outputs.type == 'minor' @@ -107,8 +91,8 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} - NUMBER: ${{ steps.pr.outputs.number }} - BASE_REF: ${{ steps.pr.outputs.base-ref }} + NUMBER: ${{ steps.semver.outputs.pr-number }} + BASE_REF: ${{ steps.semver.outputs.base-ref }} - name: Add label semver:major if: github.event.workflow_run.conclusion == 'success' && steps.semver.outputs.type == 'major' @@ -116,7 +100,7 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} - NUMBER: ${{ steps.pr.outputs.number }} + NUMBER: ${{ steps.semver.outputs.pr-number }} edits: if: github.event_name == 'pull_request_target' diff --git a/.github/workflows/semver.yaml b/.github/workflows/semver.yaml index 5d54e77299..9ccbca0fde 100644 --- a/.github/workflows/semver.yaml +++ b/.github/workflows/semver.yaml @@ -51,8 +51,12 @@ jobs: run: | mkdir -p semver-results echo "$SEMVER_TYPE" > semver-results/semver-type + echo "$PR_NUMBER" > semver-results/pr-number + echo "$BASE_REF" > semver-results/base-ref env: SEMVER_TYPE: ${{ steps.go-apidiff.outputs.semver-type }} + PR_NUMBER: ${{ github.event.pull_request.number }} + BASE_REF: ${{ github.base_ref }} - name: Upload semver results if: always() From 553a7e978052b5d958f3bc2d2c9069ee88cbfb84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Thu, 26 Mar 2026 10:23:36 +0100 Subject: [PATCH 341/429] ci: add dependabot cooldown configuration Add a 7-day cooldown to all Dependabot package ecosystem entries. This reduces supply-chain risk by waiting for newly released versions to be vetted before automatically proposing updates, and avoids pulling in compromised versions before they can be taken down. Reported by zizmor (dependabot-cooldown). --- .github/dependabot.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml index 2b5c704536..b061387fea 100644 --- a/.github/dependabot.yaml +++ b/.github/dependabot.yaml @@ -4,9 +4,13 @@ updates: directory: "/" schedule: interval: daily + cooldown: + default-days: 7 open-pull-requests-limit: 10 - package-ecosystem: "github-actions" directory: "/" - schedule: + schedule: interval: daily + cooldown: + default-days: 7 open-pull-requests-limit: 10 From d14dbe9b97c9722392998237d1cdd29660de6541 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Thu, 26 Mar 2026 10:23:49 +0100 Subject: [PATCH 342/429] ci: expand zizmor scan scope to cover dependabot config Widen the path filter from .github/workflows/** to .github/** so that changes to .github/dependabot.yaml also trigger the zizmor security scan. --- .github/workflows/zizmor.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/zizmor.yaml b/.github/workflows/zizmor.yaml index 494a54ed80..e9b06d69ac 100644 --- a/.github/workflows/zizmor.yaml +++ b/.github/workflows/zizmor.yaml @@ -5,10 +5,10 @@ on: branches: - master paths: - - '.github/workflows/**' + - '.github/**' pull_request: paths: - - '.github/workflows/**' + - '.github/**' permissions: {} From 9e2872b16d371a62181c5242023728806a4b79c6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Mar 2026 10:09:22 +0000 Subject: [PATCH 343/429] build(deps): bump actions/download-artifact from 4.3.0 to 8.0.1 Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4.3.0 to 8.0.1. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/d3f86a106a0bac45b974a628896c90dbdf5c8093...3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: 8.0.1 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/label-pr.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/label-pr.yaml b/.github/workflows/label-pr.yaml index c876bf6625..de5d9a52b0 100644 --- a/.github/workflows/label-pr.yaml +++ b/.github/workflows/label-pr.yaml @@ -28,7 +28,7 @@ jobs: pull-requests: write steps: - name: Download semver results - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: semver-results run-id: ${{ github.event.workflow_run.id }} From 058f51767ad291edaead030a5711d5a8af04a9b2 Mon Sep 17 00:00:00 2001 From: Dominik Danelski Date: Fri, 27 Mar 2026 13:11:08 +0100 Subject: [PATCH 344/429] Use SkipReleasesBelow instead of SkipRelease in traits_test Signed-off-by: Dominik Danelski --- .../openstack/placement/v1/traits_test.go | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/internal/acceptance/openstack/placement/v1/traits_test.go b/internal/acceptance/openstack/placement/v1/traits_test.go index 3099da80df..15775f5281 100644 --- a/internal/acceptance/openstack/placement/v1/traits_test.go +++ b/internal/acceptance/openstack/placement/v1/traits_test.go @@ -17,9 +17,7 @@ import ( func TestTraitsList(t *testing.T) { // The Traits API requires microversion 1.6 or later - clients.SkipRelease(t, "stable/mitaka") - clients.SkipRelease(t, "stable/newton") - clients.SkipRelease(t, "stable/ocata") + clients.SkipReleasesBelow(t, "stable/pike") client, err := clients.NewPlacementV1Client() th.AssertNoErr(t, err) @@ -39,9 +37,7 @@ func TestTraitsList(t *testing.T) { func TestTraitGet(t *testing.T) { // The Traits API requires microversion 1.6 or later - clients.SkipRelease(t, "stable/mitaka") - clients.SkipRelease(t, "stable/newton") - clients.SkipRelease(t, "stable/ocata") + clients.SkipReleasesBelow(t, "stable/pike") client, err := clients.NewPlacementV1Client() th.AssertNoErr(t, err) @@ -56,9 +52,7 @@ func TestTraitGet(t *testing.T) { func TestTraitGetNegative(t *testing.T) { // The Traits API requires microversion 1.6 or later - clients.SkipRelease(t, "stable/mitaka") - clients.SkipRelease(t, "stable/newton") - clients.SkipRelease(t, "stable/ocata") + clients.SkipReleasesBelow(t, "stable/pike") client, err := clients.NewPlacementV1Client() th.AssertNoErr(t, err) @@ -72,9 +66,7 @@ func TestTraitGetNegative(t *testing.T) { func TestTraitsListFiltering(t *testing.T) { // The Traits API requires microversion 1.6 or later - clients.SkipRelease(t, "stable/mitaka") - clients.SkipRelease(t, "stable/newton") - clients.SkipRelease(t, "stable/ocata") + clients.SkipReleasesBelow(t, "stable/pike") client, err := clients.NewPlacementV1Client() th.AssertNoErr(t, err) From 9400749ff595475f23f017d9f8955750dfee928c Mon Sep 17 00:00:00 2001 From: Dominik Danelski Date: Thu, 26 Mar 2026 19:39:01 +0100 Subject: [PATCH 345/429] Implement CREATE operation on Placement traits Related: #526 API reference: https://docs.openstack.org/api-ref/placement/#traits Code reference: https://github.com/openstack/placement/blob/stable/2025.1/placement/handlers/trait.py#L67-L103 Signed-off-by: Dominik Danelski --- .../openstack/placement/v1/traits_test.go | 59 +++++++++++++++++++ openstack/placement/v1/traits/doc.go | 13 ++++ openstack/placement/v1/traits/requests.go | 29 +++++++++ openstack/placement/v1/traits/results.go | 6 ++ .../v1/traits/testing/fixtures_test.go | 32 ++++++++++ .../v1/traits/testing/requests_test.go | 30 ++++++++++ openstack/placement/v1/traits/urls.go | 4 ++ 7 files changed, 173 insertions(+) diff --git a/internal/acceptance/openstack/placement/v1/traits_test.go b/internal/acceptance/openstack/placement/v1/traits_test.go index 15775f5281..180a85282a 100644 --- a/internal/acceptance/openstack/placement/v1/traits_test.go +++ b/internal/acceptance/openstack/placement/v1/traits_test.go @@ -11,6 +11,7 @@ import ( "github.com/gophercloud/gophercloud/v2" "github.com/gophercloud/gophercloud/v2/internal/acceptance/clients" + "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/traits" th "github.com/gophercloud/gophercloud/v2/testhelper" ) @@ -88,3 +89,61 @@ func TestTraitsListFiltering(t *testing.T) { th.AssertEquals(t, true, strings.HasPrefix(trait, "HW_")) } } + +func TestTraitsCreateSuccess(t *testing.T) { + // The Traits API requires microversion 1.6 or later + clients.SkipReleasesBelow(t, "stable/pike") + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + client.Microversion = "1.6" + + traitName := strings.ToUpper(tools.RandomString("CUSTOM_", 8)) + createOpts := traits.CreateOpts{} + + err = traits.Create(context.TODO(), client, traitName, createOpts).ExtractErr() + th.AssertNoErr(t, err) + + // Assert that the trait now exists + err = traits.Get(context.TODO(), client, traitName).ExtractErr() + th.AssertNoErr(t, err) +} + +func TestTraitsCreateDuplicate(t *testing.T) { + // The Traits API requires microversion 1.6 or later + clients.SkipReleasesBelow(t, "stable/pike") + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + client.Microversion = "1.6" + + traitName := strings.ToUpper(tools.RandomString("CUSTOM_", 8)) + createOpts := traits.CreateOpts{} + + // Create the trait for the first time + err = traits.Create(context.TODO(), client, traitName, createOpts).ExtractErr() + th.AssertNoErr(t, err) + + // Creating the same trait again results in 204 (no error) + err = traits.Create(context.TODO(), client, traitName, createOpts).ExtractErr() + th.AssertNoErr(t, err) +} + +// Test of creating a trait name that cannot be created in an API +func TestTraitsCreateInvalidName(t *testing.T) { + // The Traits API requires microversion 1.6 or later + clients.SkipReleasesBelow(t, "stable/pike") + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + client.Microversion = "1.6" + + traitName := "HW_WE_CANNOT_CREATE_THIS_TRAIT" + createOpts := traits.CreateOpts{} + + err = traits.Create(context.TODO(), client, traitName, createOpts).ExtractErr() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) +} diff --git a/openstack/placement/v1/traits/doc.go b/openstack/placement/v1/traits/doc.go index e11afc158e..215f8bd9a4 100644 --- a/openstack/placement/v1/traits/doc.go +++ b/openstack/placement/v1/traits/doc.go @@ -38,5 +38,18 @@ Example to check if a trait exists } else { fmt.Println("Trait exists!") } + +Example to create a trait + + placementClient.Microversion = "1.6" + + traitName := "CUSTOM_HW_FPGA_CLASS1" + createOpts := traits.CreateOpts{} + err := traits.Create(context.TODO(), placementClient, traitName, createOpts).ExtractErr() + if err != nil { + panic(err) + } else { + fmt.Println("Trait created successfully!") + } */ package traits diff --git a/openstack/placement/v1/traits/requests.go b/openstack/placement/v1/traits/requests.go index 82fd8a0dbb..67f21a6f02 100644 --- a/openstack/placement/v1/traits/requests.go +++ b/openstack/placement/v1/traits/requests.go @@ -58,3 +58,32 @@ func Get(ctx context.Context, client *gophercloud.ServiceClient, traitName strin _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return } + +// CreateOptsBuilder allows extensions to add additional parameters to +// the Create request. +type CreateOptsBuilder interface { + ToTraitCreateMap() (map[string]any, error) +} + +// CreateOpts provides options used to create a trait. +type CreateOpts struct { +} + +// ToTraitCreateMap formats a CreateOpts into a create request. +func (opts CreateOpts) ToTraitCreateMap() (map[string]any, error) { + return gophercloud.BuildRequestBody(opts, "") +} + +// Create creates a new trait. +func Create(ctx context.Context, client *gophercloud.ServiceClient, traitName string, opts CreateOptsBuilder) (r CreateResult) { + b, err := opts.ToTraitCreateMap() + if err != nil { + r.Err = err + return + } + resp, err := client.Put(ctx, createURL(client, traitName), b, nil, &gophercloud.RequestOpts{ + OkCodes: []int{201, 204}, + }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} diff --git a/openstack/placement/v1/traits/results.go b/openstack/placement/v1/traits/results.go index 5e638cf226..0718b64601 100644 --- a/openstack/placement/v1/traits/results.go +++ b/openstack/placement/v1/traits/results.go @@ -16,6 +16,12 @@ type TraitsPage struct { pagination.SinglePageBase } +// CreateResult is the response from a Create operation. Call its ExtractErr to +// determine if the request succeeded or failed. +type CreateResult struct { + gophercloud.ErrResult +} + // IsEmpty satisfies the IsEmpty method of the Page interface. It returns true // if a List contains no results. func (r TraitsPage) IsEmpty() (bool, error) { diff --git a/openstack/placement/v1/traits/testing/fixtures_test.go b/openstack/placement/v1/traits/testing/fixtures_test.go index 6c37649d18..9a22bcb7d2 100644 --- a/openstack/placement/v1/traits/testing/fixtures_test.go +++ b/openstack/placement/v1/traits/testing/fixtures_test.go @@ -11,6 +11,7 @@ import ( const PresentTrait = "CUSTOM_HW_FPGA_CLASS1" const AbsentTrait = "NON_EXISTENT_TRAIT" +const CustomTraitToCreate = "CUSTOM_TRAIT_TO_CREATE" const TraitsListResultAll = ` { @@ -106,3 +107,34 @@ func HandleGetTraitNotFound(t *testing.T, fakeServer th.FakeServer) { w.WriteHeader(http.StatusNotFound) }) } + +func HandleCreateTraitSuccess(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/traits/"+CustomTraitToCreate, + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "PUT") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.WriteHeader(http.StatusCreated) + }) +} + +func HandleCreateTraitThatAlreadyExists(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/traits/"+PresentTrait, + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "PUT") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.WriteHeader(http.StatusNoContent) + }) +} + +// Trait names created via the API must be prefixed with CUSTOM_. +func HandleCreateTraitInvalidName(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/traits/"+AbsentTrait, + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "PUT") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.WriteHeader(http.StatusBadRequest) + }) +} diff --git a/openstack/placement/v1/traits/testing/requests_test.go b/openstack/placement/v1/traits/testing/requests_test.go index 39642afb91..f3ba58f127 100644 --- a/openstack/placement/v1/traits/testing/requests_test.go +++ b/openstack/placement/v1/traits/testing/requests_test.go @@ -99,3 +99,33 @@ func TestGetTraitNotFound(t *testing.T) { err := traits.Get(context.TODO(), client.ServiceClient(fakeServer), AbsentTrait).ExtractErr() th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } + +func TestCreateTraitSuccess(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleCreateTraitSuccess(t, fakeServer) + + err := traits.Create(context.TODO(), client.ServiceClient(fakeServer), CustomTraitToCreate, traits.CreateOpts{}).ExtractErr() + th.AssertNoErr(t, err) +} + +func TestCreateTraitThatAlreadyExists(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleCreateTraitThatAlreadyExists(t, fakeServer) + + err := traits.Create(context.TODO(), client.ServiceClient(fakeServer), PresentTrait, traits.CreateOpts{}).ExtractErr() + th.AssertNoErr(t, err) +} + +func TestCreateTraitInvalidName(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleCreateTraitInvalidName(t, fakeServer) + + err := traits.Create(context.TODO(), client.ServiceClient(fakeServer), AbsentTrait, traits.CreateOpts{}).ExtractErr() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) +} diff --git a/openstack/placement/v1/traits/urls.go b/openstack/placement/v1/traits/urls.go index a6ea7757a1..2211abb309 100644 --- a/openstack/placement/v1/traits/urls.go +++ b/openstack/placement/v1/traits/urls.go @@ -13,3 +13,7 @@ func listURL(client *gophercloud.ServiceClient) string { func getURL(client *gophercloud.ServiceClient, traitName string) string { return client.ServiceURL(apiName, traitName) } + +func createURL(client *gophercloud.ServiceClient, traitName string) string { + return client.ServiceURL(apiName, traitName) +} From feee1069392a8e508e77665d6d1075cd6cb74a12 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Mar 2026 09:08:53 +0000 Subject: [PATCH 346/429] build(deps): bump actions/setup-go from 6.3.0 to 6.4.0 Bumps [actions/setup-go](https://github.com/actions/setup-go) from 6.3.0 to 6.4.0. - [Release notes](https://github.com/actions/setup-go/releases) - [Commits](https://github.com/actions/setup-go/compare/4b73464bb391d4059bd26b0524d20df3927bd417...4a3601121dd01d1626a1e23e37211e3254c1c06c) --- updated-dependencies: - dependency-name: actions/setup-go dependency-version: 6.4.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql-analysis.yaml | 2 +- .github/workflows/functional-baremetal.yaml | 2 +- .github/workflows/functional-basic.yaml | 2 +- .github/workflows/functional-blockstorage.yaml | 2 +- .github/workflows/functional-compute.yaml | 2 +- .github/workflows/functional-containerinfra.yaml | 2 +- .github/workflows/functional-dns.yaml | 2 +- .github/workflows/functional-fwaas_v2.yaml | 2 +- .github/workflows/functional-identity.yaml | 2 +- .github/workflows/functional-image.yaml | 2 +- .github/workflows/functional-keymanager.yaml | 2 +- .github/workflows/functional-loadbalancer.yaml | 2 +- .github/workflows/functional-messaging.yaml | 2 +- .github/workflows/functional-networking.yaml | 2 +- .github/workflows/functional-objectstorage.yaml | 2 +- .github/workflows/functional-orchestration.yaml | 2 +- .github/workflows/functional-placement.yaml | 2 +- .github/workflows/functional-sharedfilesystems.yaml | 2 +- .github/workflows/functional-workflow.yaml | 2 +- .github/workflows/lint.yaml | 2 +- .github/workflows/semver.yaml | 2 +- .github/workflows/unit.yaml | 2 +- 22 files changed, 22 insertions(+), 22 deletions(-) diff --git a/.github/workflows/codeql-analysis.yaml b/.github/workflows/codeql-analysis.yaml index 3040b3cc41..12d4008b74 100644 --- a/.github/workflows/codeql-analysis.yaml +++ b/.github/workflows/codeql-analysis.yaml @@ -23,7 +23,7 @@ jobs: persist-credentials: false - name: Setup Go - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-baremetal.yaml b/.github/workflows/functional-baremetal.yaml index 7021620482..7248cbf947 100644 --- a/.github/workflows/functional-baremetal.yaml +++ b/.github/workflows/functional-baremetal.yaml @@ -101,7 +101,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-basic.yaml b/.github/workflows/functional-basic.yaml index 8964c0b550..313d67c2d3 100644 --- a/.github/workflows/functional-basic.yaml +++ b/.github/workflows/functional-basic.yaml @@ -55,7 +55,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-blockstorage.yaml b/.github/workflows/functional-blockstorage.yaml index 4d981062d1..f067e785ce 100644 --- a/.github/workflows/functional-blockstorage.yaml +++ b/.github/workflows/functional-blockstorage.yaml @@ -61,7 +61,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-compute.yaml b/.github/workflows/functional-compute.yaml index 46c7cb41bd..b2d2f27701 100644 --- a/.github/workflows/functional-compute.yaml +++ b/.github/workflows/functional-compute.yaml @@ -61,7 +61,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-containerinfra.yaml b/.github/workflows/functional-containerinfra.yaml index 294624b0f1..8edabce192 100644 --- a/.github/workflows/functional-containerinfra.yaml +++ b/.github/workflows/functional-containerinfra.yaml @@ -88,7 +88,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-dns.yaml b/.github/workflows/functional-dns.yaml index 7abe11855f..5ad1d8771f 100644 --- a/.github/workflows/functional-dns.yaml +++ b/.github/workflows/functional-dns.yaml @@ -69,7 +69,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-fwaas_v2.yaml b/.github/workflows/functional-fwaas_v2.yaml index b3f381756e..97cbb3f716 100644 --- a/.github/workflows/functional-fwaas_v2.yaml +++ b/.github/workflows/functional-fwaas_v2.yaml @@ -84,7 +84,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-identity.yaml b/.github/workflows/functional-identity.yaml index 7bdbf7ab9c..651e59bc3d 100644 --- a/.github/workflows/functional-identity.yaml +++ b/.github/workflows/functional-identity.yaml @@ -59,7 +59,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-image.yaml b/.github/workflows/functional-image.yaml index 8254a7d0c8..e9e688044d 100644 --- a/.github/workflows/functional-image.yaml +++ b/.github/workflows/functional-image.yaml @@ -59,7 +59,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-keymanager.yaml b/.github/workflows/functional-keymanager.yaml index fee5e6603b..e312e034a0 100644 --- a/.github/workflows/functional-keymanager.yaml +++ b/.github/workflows/functional-keymanager.yaml @@ -75,7 +75,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-loadbalancer.yaml b/.github/workflows/functional-loadbalancer.yaml index 3886f48146..8a80c2ea5e 100644 --- a/.github/workflows/functional-loadbalancer.yaml +++ b/.github/workflows/functional-loadbalancer.yaml @@ -75,7 +75,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-messaging.yaml b/.github/workflows/functional-messaging.yaml index fc7de2d4ad..3aba20dd6f 100644 --- a/.github/workflows/functional-messaging.yaml +++ b/.github/workflows/functional-messaging.yaml @@ -62,7 +62,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-networking.yaml b/.github/workflows/functional-networking.yaml index 1ff2ce14fc..b93e3c1f2c 100644 --- a/.github/workflows/functional-networking.yaml +++ b/.github/workflows/functional-networking.yaml @@ -79,7 +79,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-objectstorage.yaml b/.github/workflows/functional-objectstorage.yaml index 04f1a6d56a..2b3db097d0 100644 --- a/.github/workflows/functional-objectstorage.yaml +++ b/.github/workflows/functional-objectstorage.yaml @@ -65,7 +65,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-orchestration.yaml b/.github/workflows/functional-orchestration.yaml index 0eaf8885a6..dbd5d36668 100644 --- a/.github/workflows/functional-orchestration.yaml +++ b/.github/workflows/functional-orchestration.yaml @@ -61,7 +61,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-placement.yaml b/.github/workflows/functional-placement.yaml index 99eb3cca0b..641b22e9bc 100644 --- a/.github/workflows/functional-placement.yaml +++ b/.github/workflows/functional-placement.yaml @@ -59,7 +59,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-sharedfilesystems.yaml b/.github/workflows/functional-sharedfilesystems.yaml index 426111ed36..e8fc1a03a6 100644 --- a/.github/workflows/functional-sharedfilesystems.yaml +++ b/.github/workflows/functional-sharedfilesystems.yaml @@ -83,7 +83,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-workflow.yaml b/.github/workflows/functional-workflow.yaml index dc4030ba77..bb57db4067 100644 --- a/.github/workflows/functional-workflow.yaml +++ b/.github/workflows/functional-workflow.yaml @@ -64,7 +64,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index b019a83b55..88784d2215 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -13,7 +13,7 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false - - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/semver.yaml b/.github/workflows/semver.yaml index 121a29d2c7..af9ff9643d 100644 --- a/.github/workflows/semver.yaml +++ b/.github/workflows/semver.yaml @@ -28,7 +28,7 @@ jobs: GIT_SEQUENCE_EDITOR: '/usr/bin/true' BASE_REF: ${{ github.base_ref }} - - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/unit.yaml b/.github/workflows/unit.yaml index c938fd0a8c..fd82541b38 100644 --- a/.github/workflows/unit.yaml +++ b/.github/workflows/unit.yaml @@ -19,7 +19,7 @@ jobs: with: persist-credentials: false - name: Setup Go - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 with: go-version-file: 'go.mod' cache: true From 3a2ad5ae9e6a1eb4b5282d3424c2b931e0a6d76d Mon Sep 17 00:00:00 2001 From: Dominik Danelski Date: Mon, 30 Mar 2026 12:58:55 +0200 Subject: [PATCH 347/429] Update traits doc to include a wider range of available operations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martin André --- openstack/placement/v1/traits/doc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openstack/placement/v1/traits/doc.go b/openstack/placement/v1/traits/doc.go index 215f8bd9a4..f6c88a62fb 100644 --- a/openstack/placement/v1/traits/doc.go +++ b/openstack/placement/v1/traits/doc.go @@ -1,5 +1,5 @@ /* -Package traits lists traits from the OpenStack Placement service. +Package traits manages traits from the OpenStack Placement service. Traits API requests are available starting from microversion 1.6. From 5c4a59ac74025ba8ef8228b75e4b5cfebff64956 Mon Sep 17 00:00:00 2001 From: Dominik Danelski Date: Mon, 30 Mar 2026 17:12:44 +0200 Subject: [PATCH 348/429] Simplify trait PUT operation, remove CreateOptsBuilder It's useless, as API doesn't take any arguments at the moment. That's unlikely to change in the near future. Signed-off-by: Dominik Danelski --- .../openstack/placement/v1/traits_test.go | 11 ++++----- openstack/placement/v1/traits/doc.go | 3 +-- openstack/placement/v1/traits/requests.go | 24 ++----------------- .../v1/traits/testing/requests_test.go | 6 ++--- 4 files changed, 10 insertions(+), 34 deletions(-) diff --git a/internal/acceptance/openstack/placement/v1/traits_test.go b/internal/acceptance/openstack/placement/v1/traits_test.go index 180a85282a..8ceeb42aee 100644 --- a/internal/acceptance/openstack/placement/v1/traits_test.go +++ b/internal/acceptance/openstack/placement/v1/traits_test.go @@ -100,9 +100,8 @@ func TestTraitsCreateSuccess(t *testing.T) { client.Microversion = "1.6" traitName := strings.ToUpper(tools.RandomString("CUSTOM_", 8)) - createOpts := traits.CreateOpts{} - err = traits.Create(context.TODO(), client, traitName, createOpts).ExtractErr() + err = traits.Create(context.TODO(), client, traitName).ExtractErr() th.AssertNoErr(t, err) // Assert that the trait now exists @@ -120,14 +119,13 @@ func TestTraitsCreateDuplicate(t *testing.T) { client.Microversion = "1.6" traitName := strings.ToUpper(tools.RandomString("CUSTOM_", 8)) - createOpts := traits.CreateOpts{} // Create the trait for the first time - err = traits.Create(context.TODO(), client, traitName, createOpts).ExtractErr() + err = traits.Create(context.TODO(), client, traitName).ExtractErr() th.AssertNoErr(t, err) // Creating the same trait again results in 204 (no error) - err = traits.Create(context.TODO(), client, traitName, createOpts).ExtractErr() + err = traits.Create(context.TODO(), client, traitName).ExtractErr() th.AssertNoErr(t, err) } @@ -142,8 +140,7 @@ func TestTraitsCreateInvalidName(t *testing.T) { client.Microversion = "1.6" traitName := "HW_WE_CANNOT_CREATE_THIS_TRAIT" - createOpts := traits.CreateOpts{} - err = traits.Create(context.TODO(), client, traitName, createOpts).ExtractErr() + err = traits.Create(context.TODO(), client, traitName).ExtractErr() th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) } diff --git a/openstack/placement/v1/traits/doc.go b/openstack/placement/v1/traits/doc.go index f6c88a62fb..91c7a8888e 100644 --- a/openstack/placement/v1/traits/doc.go +++ b/openstack/placement/v1/traits/doc.go @@ -44,8 +44,7 @@ Example to create a trait placementClient.Microversion = "1.6" traitName := "CUSTOM_HW_FPGA_CLASS1" - createOpts := traits.CreateOpts{} - err := traits.Create(context.TODO(), placementClient, traitName, createOpts).ExtractErr() + err := traits.Create(context.TODO(), placementClient, traitName).ExtractErr() if err != nil { panic(err) } else { diff --git a/openstack/placement/v1/traits/requests.go b/openstack/placement/v1/traits/requests.go index 67f21a6f02..2a106ff013 100644 --- a/openstack/placement/v1/traits/requests.go +++ b/openstack/placement/v1/traits/requests.go @@ -59,29 +59,9 @@ func Get(ctx context.Context, client *gophercloud.ServiceClient, traitName strin return } -// CreateOptsBuilder allows extensions to add additional parameters to -// the Create request. -type CreateOptsBuilder interface { - ToTraitCreateMap() (map[string]any, error) -} - -// CreateOpts provides options used to create a trait. -type CreateOpts struct { -} - -// ToTraitCreateMap formats a CreateOpts into a create request. -func (opts CreateOpts) ToTraitCreateMap() (map[string]any, error) { - return gophercloud.BuildRequestBody(opts, "") -} - // Create creates a new trait. -func Create(ctx context.Context, client *gophercloud.ServiceClient, traitName string, opts CreateOptsBuilder) (r CreateResult) { - b, err := opts.ToTraitCreateMap() - if err != nil { - r.Err = err - return - } - resp, err := client.Put(ctx, createURL(client, traitName), b, nil, &gophercloud.RequestOpts{ +func Create(ctx context.Context, client *gophercloud.ServiceClient, traitName string) (r CreateResult) { + resp, err := client.Put(ctx, createURL(client, traitName), nil, nil, &gophercloud.RequestOpts{ OkCodes: []int{201, 204}, }) _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) diff --git a/openstack/placement/v1/traits/testing/requests_test.go b/openstack/placement/v1/traits/testing/requests_test.go index f3ba58f127..9f5b63663d 100644 --- a/openstack/placement/v1/traits/testing/requests_test.go +++ b/openstack/placement/v1/traits/testing/requests_test.go @@ -106,7 +106,7 @@ func TestCreateTraitSuccess(t *testing.T) { HandleCreateTraitSuccess(t, fakeServer) - err := traits.Create(context.TODO(), client.ServiceClient(fakeServer), CustomTraitToCreate, traits.CreateOpts{}).ExtractErr() + err := traits.Create(context.TODO(), client.ServiceClient(fakeServer), CustomTraitToCreate).ExtractErr() th.AssertNoErr(t, err) } @@ -116,7 +116,7 @@ func TestCreateTraitThatAlreadyExists(t *testing.T) { HandleCreateTraitThatAlreadyExists(t, fakeServer) - err := traits.Create(context.TODO(), client.ServiceClient(fakeServer), PresentTrait, traits.CreateOpts{}).ExtractErr() + err := traits.Create(context.TODO(), client.ServiceClient(fakeServer), PresentTrait).ExtractErr() th.AssertNoErr(t, err) } @@ -126,6 +126,6 @@ func TestCreateTraitInvalidName(t *testing.T) { HandleCreateTraitInvalidName(t, fakeServer) - err := traits.Create(context.TODO(), client.ServiceClient(fakeServer), AbsentTrait, traits.CreateOpts{}).ExtractErr() + err := traits.Create(context.TODO(), client.ServiceClient(fakeServer), AbsentTrait).ExtractErr() th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) } From 990245747c4425342c574da0bac4e01cb076b0d1 Mon Sep 17 00:00:00 2001 From: Dominik Danelski Date: Thu, 26 Mar 2026 22:28:27 +0100 Subject: [PATCH 349/429] Implement DELETE operation on Placement traits Related: #526 API reference: https://docs.openstack.org/api-ref/placement/#traits Code reference: https://github.com/openstack/placement/blob/stable/2025.1/placement/handlers/trait.py#L129-L146 Signed-off-by: Dominik Danelski --- .../openstack/placement/v1/traits_test.go | 56 +++++++++++++++++++ openstack/placement/v1/traits/doc.go | 12 ++++ openstack/placement/v1/traits/requests.go | 9 +++ openstack/placement/v1/traits/results.go | 6 ++ .../v1/traits/testing/fixtures_test.go | 42 ++++++++++++++ .../v1/traits/testing/requests_test.go | 40 +++++++++++++ openstack/placement/v1/traits/urls.go | 4 ++ 7 files changed, 169 insertions(+) diff --git a/internal/acceptance/openstack/placement/v1/traits_test.go b/internal/acceptance/openstack/placement/v1/traits_test.go index 8ceeb42aee..0bea5ef944 100644 --- a/internal/acceptance/openstack/placement/v1/traits_test.go +++ b/internal/acceptance/openstack/placement/v1/traits_test.go @@ -144,3 +144,59 @@ func TestTraitsCreateInvalidName(t *testing.T) { err = traits.Create(context.TODO(), client, traitName).ExtractErr() th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) } + +func TestTraitsDeleteSuccess(t *testing.T) { + // The Traits API requires microversion 1.6 or later + clients.SkipReleasesBelow(t, "stable/pike") + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + client.Microversion = "1.6" + + traitName := strings.ToUpper(tools.RandomString("CUSTOM_", 8)) + + // Prepare: Create the trait + err = traits.Create(context.TODO(), client, traitName).ExtractErr() + th.AssertNoErr(t, err) + + // Act: Delete the trait + err = traits.Delete(context.TODO(), client, traitName).ExtractErr() + th.AssertNoErr(t, err) + + // Assert: The trait no longer exists + err = traits.Get(context.TODO(), client, traitName).ExtractErr() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) +} + +func TestTraitsDeleteNotFound(t *testing.T) { + // The Traits API requires microversion 1.6 or later + clients.SkipReleasesBelow(t, "stable/pike") + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + client.Microversion = "1.6" + + traitName := strings.ToUpper(tools.RandomString("CUSTOM_", 8)) + + err = traits.Delete(context.TODO(), client, traitName).ExtractErr() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) +} + +// API does allow manipulation solely of custom traits, +// so trying to delete a standard trait should fail. +func TestTraitsDeleteStandardTraitFailure(t *testing.T) { + // The Traits API requires microversion 1.6 or later + clients.SkipReleasesBelow(t, "stable/pike") + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + client.Microversion = "1.6" + + traitName := "COMPUTE_NODE" + + err = traits.Delete(context.TODO(), client, traitName).ExtractErr() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) +} diff --git a/openstack/placement/v1/traits/doc.go b/openstack/placement/v1/traits/doc.go index 91c7a8888e..d2774d9f29 100644 --- a/openstack/placement/v1/traits/doc.go +++ b/openstack/placement/v1/traits/doc.go @@ -50,5 +50,17 @@ Example to create a trait } else { fmt.Println("Trait created successfully!") } + +Example to delete a trait + + placementClient.Microversion = "1.6" + + traitName := "CUSTOM_HW_FPGA_CLASS1" + err := traits.Delete(context.TODO(), placementClient, traitName).ExtractErr() + if err != nil { + panic(err) + } else { + fmt.Println("Trait deleted successfully!") + } */ package traits diff --git a/openstack/placement/v1/traits/requests.go b/openstack/placement/v1/traits/requests.go index 2a106ff013..99e9b58434 100644 --- a/openstack/placement/v1/traits/requests.go +++ b/openstack/placement/v1/traits/requests.go @@ -67,3 +67,12 @@ func Create(ctx context.Context, client *gophercloud.ServiceClient, traitName st _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return } + +// Delete deletes the trait specified by name. +func Delete(ctx context.Context, client *gophercloud.ServiceClient, traitName string) (r DeleteResult) { + resp, err := client.Delete(ctx, deleteURL(client, traitName), &gophercloud.RequestOpts{ + OkCodes: []int{204}, + }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} diff --git a/openstack/placement/v1/traits/results.go b/openstack/placement/v1/traits/results.go index 0718b64601..085de1daf0 100644 --- a/openstack/placement/v1/traits/results.go +++ b/openstack/placement/v1/traits/results.go @@ -22,6 +22,12 @@ type CreateResult struct { gophercloud.ErrResult } +// DeleteResult is the response from a Delete operation. Call its ExtractErr to +// determine if the request succeeded or failed. +type DeleteResult struct { + gophercloud.ErrResult +} + // IsEmpty satisfies the IsEmpty method of the Page interface. It returns true // if a List contains no results. func (r TraitsPage) IsEmpty() (bool, error) { diff --git a/openstack/placement/v1/traits/testing/fixtures_test.go b/openstack/placement/v1/traits/testing/fixtures_test.go index 9a22bcb7d2..3a8eb9446a 100644 --- a/openstack/placement/v1/traits/testing/fixtures_test.go +++ b/openstack/placement/v1/traits/testing/fixtures_test.go @@ -12,6 +12,8 @@ import ( const PresentTrait = "CUSTOM_HW_FPGA_CLASS1" const AbsentTrait = "NON_EXISTENT_TRAIT" const CustomTraitToCreate = "CUSTOM_TRAIT_TO_CREATE" +const CustomTraitToDelete = CustomTraitToCreate +const StandardHardwareTrait = "HW_CPU_X86_AVX" const TraitsListResultAll = ` { @@ -138,3 +140,43 @@ func HandleCreateTraitInvalidName(t *testing.T, fakeServer th.FakeServer) { w.WriteHeader(http.StatusBadRequest) }) } + +func HandleDeleteTraitSuccess(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/traits/"+CustomTraitToDelete, + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "DELETE") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.WriteHeader(http.StatusNoContent) + }) +} + +func HandleDeleteTraitNotFound(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/traits/"+AbsentTrait, + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "DELETE") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.WriteHeader(http.StatusNotFound) + }) +} + +func HandleDeleteStandardTraitFailure(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/traits/"+StandardHardwareTrait, + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "DELETE") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.WriteHeader(http.StatusBadRequest) + }) +} + +func HandleDeleteTraitInUseFailure(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/traits/"+PresentTrait, + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "DELETE") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.WriteHeader(http.StatusConflict) + }) +} diff --git a/openstack/placement/v1/traits/testing/requests_test.go b/openstack/placement/v1/traits/testing/requests_test.go index 9f5b63663d..ecd08005d4 100644 --- a/openstack/placement/v1/traits/testing/requests_test.go +++ b/openstack/placement/v1/traits/testing/requests_test.go @@ -129,3 +129,43 @@ func TestCreateTraitInvalidName(t *testing.T) { err := traits.Create(context.TODO(), client.ServiceClient(fakeServer), AbsentTrait).ExtractErr() th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) } + +func TestDeleteTraitSuccess(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleDeleteTraitSuccess(t, fakeServer) + + err := traits.Delete(context.TODO(), client.ServiceClient(fakeServer), CustomTraitToDelete).ExtractErr() + th.AssertNoErr(t, err) +} + +func TestDeleteTraitNotFound(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleDeleteTraitNotFound(t, fakeServer) + + err := traits.Delete(context.TODO(), client.ServiceClient(fakeServer), AbsentTrait).ExtractErr() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) +} + +func TestDeleteStandardTraitFailure(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleDeleteStandardTraitFailure(t, fakeServer) + + err := traits.Delete(context.TODO(), client.ServiceClient(fakeServer), StandardHardwareTrait).ExtractErr() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) +} + +func TestDeleteTraitInUseFailure(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleDeleteTraitInUseFailure(t, fakeServer) + + err := traits.Delete(context.TODO(), client.ServiceClient(fakeServer), PresentTrait).ExtractErr() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusConflict)) +} diff --git a/openstack/placement/v1/traits/urls.go b/openstack/placement/v1/traits/urls.go index 2211abb309..2baba47c49 100644 --- a/openstack/placement/v1/traits/urls.go +++ b/openstack/placement/v1/traits/urls.go @@ -17,3 +17,7 @@ func getURL(client *gophercloud.ServiceClient, traitName string) string { func createURL(client *gophercloud.ServiceClient, traitName string) string { return client.ServiceURL(apiName, traitName) } + +func deleteURL(client *gophercloud.ServiceClient, traitName string) string { + return client.ServiceURL(apiName, traitName) +} From 4f722d2a8a42fc80b5c3c84914259fafea7cd060 Mon Sep 17 00:00:00 2001 From: Dominik Danelski Date: Tue, 31 Mar 2026 15:02:02 +0200 Subject: [PATCH 350/429] Update acceptance README to remove mentions of Packstack Fixes #3667 --- internal/acceptance/README.md | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/internal/acceptance/README.md b/internal/acceptance/README.md index febf394f10..2010e368dc 100644 --- a/internal/acceptance/README.md +++ b/internal/acceptance/README.md @@ -18,16 +18,8 @@ environment. Additionally, you may incur bandwidth and service charges for the resources used, as mentioned in the note above. Therefore, it is usually best to first practice running acceptance tests in -an isolated test environment. Two options to easily create a testing -environment are [DevStack](https://docs.openstack.org/devstack/latest/) -and [PackStack](https://www.rdoproject.org/install/packstack/). - -The following blog posts detail how to create reusable PackStack environments. -These posts were written with Gophercloud in mind: - -* http://terrarum.net/blog/building-openstack-environments.html -* http://terrarum.net/blog/building-openstack-environments-2.html -* http://terrarum.net/blog/building-openstack-environments-3.html +an isolated test environment. The best option to easily create a testing +environment is [DevStack](https://docs.openstack.org/devstack/latest/). ### Step 2. Set environment variables From ff521e38909301348173e3369d9da7bb1faaba58 Mon Sep 17 00:00:00 2001 From: Dominik Danelski Date: Tue, 31 Mar 2026 17:47:24 +0200 Subject: [PATCH 351/429] Implement resource_classes GET operations Related #526 API reference: https://docs.openstack.org/api-ref/placement/#resource-classes Code reference: https://github.com/openstack/placement/blob/stable/2025.1/placement/handlers/resource_class.py#L34-L39 https://github.com/openstack/placement/blob/stable/2025.1/placement/handlers/resource_class.py#L42-L52 Signed-off-by: Dominik Danelski --- .../placement/v1/resourceclasses_test.go | 65 ++++++++++ openstack/placement/v1/resourceclasses/doc.go | 36 ++++++ .../placement/v1/resourceclasses/requests.go | 24 ++++ .../placement/v1/resourceclasses/results.go | 62 +++++++++ .../v1/resourceclasses/testing/doc.go | 2 + .../resourceclasses/testing/fixtures_test.go | 118 ++++++++++++++++++ .../resourceclasses/testing/requests_test.go | 47 +++++++ .../placement/v1/resourceclasses/urls.go | 13 ++ 8 files changed, 367 insertions(+) create mode 100644 internal/acceptance/openstack/placement/v1/resourceclasses_test.go create mode 100644 openstack/placement/v1/resourceclasses/doc.go create mode 100644 openstack/placement/v1/resourceclasses/requests.go create mode 100644 openstack/placement/v1/resourceclasses/results.go create mode 100644 openstack/placement/v1/resourceclasses/testing/doc.go create mode 100644 openstack/placement/v1/resourceclasses/testing/fixtures_test.go create mode 100644 openstack/placement/v1/resourceclasses/testing/requests_test.go create mode 100644 openstack/placement/v1/resourceclasses/urls.go diff --git a/internal/acceptance/openstack/placement/v1/resourceclasses_test.go b/internal/acceptance/openstack/placement/v1/resourceclasses_test.go new file mode 100644 index 0000000000..81673417bf --- /dev/null +++ b/internal/acceptance/openstack/placement/v1/resourceclasses_test.go @@ -0,0 +1,65 @@ +//go:build acceptance || placement || resourceclasses + +package v1 + +import ( + "context" + "net/http" + "slices" + "testing" + + "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/internal/acceptance/clients" + "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/resourceclasses" + th "github.com/gophercloud/gophercloud/v2/testhelper" +) + +func TestResourceClassesList(t *testing.T) { + // Resource classes were introduced in 1.2 + clients.SkipReleasesBelow(t, "stable/ocata") + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + client.Microversion = "1.2" + + allPages, err := resourceclasses.List(client).AllPages(context.TODO()) + th.AssertNoErr(t, err) + + allResourceClasses, err := resourceclasses.ExtractResourceClasses(allPages) + th.AssertNoErr(t, err) + + // Ensure VCPU is in the list + th.AssertEquals(t, true, slices.ContainsFunc(allResourceClasses, func(rc resourceclasses.ResourceClass) bool { + return rc.Name == "VCPU" + })) +} + +func TestResourceClassGetSuccess(t *testing.T) { + // Resource classes were introduced in 1.2 + clients.SkipReleasesBelow(t, "stable/ocata") + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + client.Microversion = "1.2" + + // VCPU is a standard resource class + rc, err := resourceclasses.Get(context.TODO(), client, "VCPU").Extract() + th.AssertNoErr(t, err) + + th.AssertEquals(t, "VCPU", rc.Name) +} + +func TestResourceClassGetNegative(t *testing.T) { + // Resource classes were introduced in 1.2 + clients.SkipReleasesBelow(t, "stable/ocata") + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + client.Microversion = "1.2" + + _, err = resourceclasses.Get(context.TODO(), client, "NON_EXISTENT_RC").Extract() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) +} diff --git a/openstack/placement/v1/resourceclasses/doc.go b/openstack/placement/v1/resourceclasses/doc.go new file mode 100644 index 0000000000..27f7c31ac8 --- /dev/null +++ b/openstack/placement/v1/resourceclasses/doc.go @@ -0,0 +1,36 @@ +/* +Package resourceclasses manages resource classes from the OpenStack Placement service. + +Resource Class API requests are available starting from microversion 1.2. + +Example to list resource classes + + placementClient.Microversion = "1.2" + + allPages, err := resourceclasses.List(placementClient).AllPages(context.TODO()) + if err != nil { + panic(err) + } + + allResourceClasses, err := resourceclasses.ExtractResourceClasses(allPages) + if err != nil { + panic(err) + } + + for _, rc := range allResourceClasses { + fmt.Printf("%+v\n", rc) + } + +Example to Get a resource class + + placementClient.Microversion = "1.2" + + resourceClassName := "VCPU" + resourceClass, err := resourceclasses.Get(context.TODO(), placementClient, resourceClassName).Extract() + if err != nil { + panic(err) + } + + fmt.Printf("%+v\n", resourceClass) +*/ +package resourceclasses diff --git a/openstack/placement/v1/resourceclasses/requests.go b/openstack/placement/v1/resourceclasses/requests.go new file mode 100644 index 0000000000..d497224aaf --- /dev/null +++ b/openstack/placement/v1/resourceclasses/requests.go @@ -0,0 +1,24 @@ +package resourceclasses + +import ( + "context" + + "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/pagination" +) + +// List retrieves a list of resource classes. +func List(client *gophercloud.ServiceClient) pagination.Pager { + url := listURL(client) + + return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page { + return ResourceClassesPage{pagination.SinglePageBase(r)} + }) +} + +// Get retrieves the resource class with the provided name. +func Get(ctx context.Context, client *gophercloud.ServiceClient, name string) (r GetResult) { + resp, err := client.Get(ctx, getURL(client, name), &r.Body, nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} diff --git a/openstack/placement/v1/resourceclasses/results.go b/openstack/placement/v1/resourceclasses/results.go new file mode 100644 index 0000000000..85ed0a4e80 --- /dev/null +++ b/openstack/placement/v1/resourceclasses/results.go @@ -0,0 +1,62 @@ +package resourceclasses + +import ( + "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/pagination" +) + +type Link struct { + Href string `json:"href"` + Rel string `json:"rel"` +} + +type ResourceClass struct { + Name string `json:"name"` + + // Links is a list of links associated with the resource class. + Links []Link `json:"links"` +} + +// resourceClassResult is the response of a base ResourceClass result. +type resourceClassResult struct { + gophercloud.Result +} + +// Extract interprets any resourceClassResult-base result as a ResourceClass. +func (r resourceClassResult) Extract() (*ResourceClass, error) { + var s ResourceClass + err := r.ExtractInto(&s) + return &s, err +} + +// GetResult represents the result of a Get operation. Call its Extract +// method to interpret it as a ResourceClass. +type GetResult struct { + resourceClassResult +} + +// ResourceClassesPage contains a single page of all resource classes from a List call. +type ResourceClassesPage struct { + pagination.SinglePageBase +} + +// IsEmpty satisfies the IsEmpty method of the Page interface. It returns true +// if a List contains no results. +func (r ResourceClassesPage) IsEmpty() (bool, error) { + if r.StatusCode == 204 { + return true, nil + } + + resourceClasses, err := ExtractResourceClasses(r) + return len(resourceClasses) == 0, err +} + +// ExtractResourceClasses takes a List result and extracts the collection of resource classes +// returned by the API. +func ExtractResourceClasses(p pagination.Page) ([]ResourceClass, error) { + var s struct { + ResourceClasses []ResourceClass `json:"resource_classes"` + } + err := (p.(ResourceClassesPage)).ExtractInto(&s) + return s.ResourceClasses, err +} diff --git a/openstack/placement/v1/resourceclasses/testing/doc.go b/openstack/placement/v1/resourceclasses/testing/doc.go new file mode 100644 index 0000000000..2a3dd0b663 --- /dev/null +++ b/openstack/placement/v1/resourceclasses/testing/doc.go @@ -0,0 +1,2 @@ +// Package testing contains resourceclasses unit tests. +package testing diff --git a/openstack/placement/v1/resourceclasses/testing/fixtures_test.go b/openstack/placement/v1/resourceclasses/testing/fixtures_test.go new file mode 100644 index 0000000000..b13e355244 --- /dev/null +++ b/openstack/placement/v1/resourceclasses/testing/fixtures_test.go @@ -0,0 +1,118 @@ +package testing + +import ( + "fmt" + "net/http" + "testing" + + "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/resourceclasses" + th "github.com/gophercloud/gophercloud/v2/testhelper" + "github.com/gophercloud/gophercloud/v2/testhelper/client" +) + +const PresentResourceClass = "CUSTOM_RESOURCE_CLASS" +const AbsentResourceClass = "NON_EXISTENT_RC" + +const ResourceClassGetResult = ` +{ + "links": [ + { + "href": "/placement/resource_classes/CUSTOM_RESOURCE_CLASS", + "rel": "self" + } + ], + "name": "CUSTOM_RESOURCE_CLASS" +} +` + +const ResourceClassesListResult = ` +{ + "resource_classes": [ + { + "name": "VCPU", + "links": [ + { + "href": "/resource_classes/VCPU", + "rel": "self" + } + ] + }, + { + "name": "CUSTOM_RESOURCE_CLASS", + "links": [ + { + "href": "/placement/resource_classes/CUSTOM_RESOURCE_CLASS", + "rel": "self" + } + ] + } + ] +} +` + +var ExpectedResourceClass = resourceclasses.ResourceClass{ + Name: "CUSTOM_RESOURCE_CLASS", + Links: []resourceclasses.Link{ + { + Href: "/placement/resource_classes/CUSTOM_RESOURCE_CLASS", + Rel: "self", + }, + }, +} + +var ExpectedResourceClassesList = []resourceclasses.ResourceClass{ + { + Name: "VCPU", + Links: []resourceclasses.Link{ + { + Href: "/resource_classes/VCPU", + Rel: "self", + }, + }, + }, + { + Name: "CUSTOM_RESOURCE_CLASS", + Links: []resourceclasses.Link{ + { + Href: "/placement/resource_classes/CUSTOM_RESOURCE_CLASS", + Rel: "self", + }, + }, + }, +} + +func HandleListResourceClasses(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/resource_classes", + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, ResourceClassesListResult) + }) +} + +func HandleGetResourceClassSuccess(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/resource_classes/"+PresentResourceClass, + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, ResourceClassGetResult) + }) +} + +func HandleGetResourceClassNotFound(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/resource_classes/"+AbsentResourceClass, + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.WriteHeader(http.StatusNotFound) + }) +} diff --git a/openstack/placement/v1/resourceclasses/testing/requests_test.go b/openstack/placement/v1/resourceclasses/testing/requests_test.go new file mode 100644 index 0000000000..4bb1f29f3c --- /dev/null +++ b/openstack/placement/v1/resourceclasses/testing/requests_test.go @@ -0,0 +1,47 @@ +package testing + +import ( + "context" + "net/http" + "testing" + + "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/resourceclasses" + th "github.com/gophercloud/gophercloud/v2/testhelper" + "github.com/gophercloud/gophercloud/v2/testhelper/client" +) + +func TestListResourceClasses(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleListResourceClasses(t, fakeServer) + + allPages, err := resourceclasses.List(client.ServiceClient(fakeServer)).AllPages(context.TODO()) + th.AssertNoErr(t, err) + + actual, err := resourceclasses.ExtractResourceClasses(allPages) + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedResourceClassesList, actual) +} + +func TestGetResourceClassSuccess(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleGetResourceClassSuccess(t, fakeServer) + + actual, err := resourceclasses.Get(context.TODO(), client.ServiceClient(fakeServer), PresentResourceClass).Extract() + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, &ExpectedResourceClass, actual) +} + +func TestGetResourceClassNotFound(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleGetResourceClassNotFound(t, fakeServer) + + _, err := resourceclasses.Get(context.TODO(), client.ServiceClient(fakeServer), AbsentResourceClass).Extract() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) +} diff --git a/openstack/placement/v1/resourceclasses/urls.go b/openstack/placement/v1/resourceclasses/urls.go new file mode 100644 index 0000000000..0fec96e30c --- /dev/null +++ b/openstack/placement/v1/resourceclasses/urls.go @@ -0,0 +1,13 @@ +package resourceclasses + +import ( + "github.com/gophercloud/gophercloud/v2" +) + +func listURL(client *gophercloud.ServiceClient) string { + return client.ServiceURL("resource_classes") +} + +func getURL(client *gophercloud.ServiceClient, name string) string { + return client.ServiceURL("resource_classes", name) +} From a07e407eb50577059d67aaf6f6b0d4d9479c6d6a Mon Sep 17 00:00:00 2001 From: Dominik Danelski Date: Tue, 31 Mar 2026 21:18:38 +0200 Subject: [PATCH 352/429] Implement resource_classes CREATE operations Related #526 API reference: https://docs.openstack.org/api-ref/placement/#resource-classes Code reference: https://github.com/openstack/placement/blob/stable/2025.1/placement/handlers/resource_class.py#L58-L85 https://github.com/openstack/placement/blob/stable/2025.1/placement/handlers/resource_class.py#L209-L240 Signed-off-by: Dominik Danelski --- .../placement/v1/resourceclasses_test.go | 94 +++++++++++++++++++ openstack/placement/v1/resourceclasses/doc.go | 22 +++++ .../placement/v1/resourceclasses/requests.go | 40 ++++++++ .../placement/v1/resourceclasses/results.go | 12 +++ .../resourceclasses/testing/fixtures_test.go | 53 +++++++++++ .../resourceclasses/testing/requests_test.go | 58 ++++++++++++ .../placement/v1/resourceclasses/urls.go | 8 ++ 7 files changed, 287 insertions(+) diff --git a/internal/acceptance/openstack/placement/v1/resourceclasses_test.go b/internal/acceptance/openstack/placement/v1/resourceclasses_test.go index 81673417bf..d2ea98fb51 100644 --- a/internal/acceptance/openstack/placement/v1/resourceclasses_test.go +++ b/internal/acceptance/openstack/placement/v1/resourceclasses_test.go @@ -6,10 +6,12 @@ import ( "context" "net/http" "slices" + "strings" "testing" "github.com/gophercloud/gophercloud/v2" "github.com/gophercloud/gophercloud/v2/internal/acceptance/clients" + "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/resourceclasses" th "github.com/gophercloud/gophercloud/v2/testhelper" ) @@ -63,3 +65,95 @@ func TestResourceClassGetNegative(t *testing.T) { _, err = resourceclasses.Get(context.TODO(), client, "NON_EXISTENT_RC").Extract() th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } + +func TestResourceClassCreateByPostSuccess(t *testing.T) { + // Resource classes were introduced in 1.2 + clients.SkipReleasesBelow(t, "stable/ocata") + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + client.Microversion = "1.2" + + name := strings.ToUpper(tools.RandomString("CUSTOM_", 8)) + createOpts := resourceclasses.CreateOpts{ + Name: name, + } + + // Act: Create a resource class using POST + err = resourceclasses.Create(context.TODO(), client, createOpts).ExtractErr() + th.AssertNoErr(t, err) + + // Assert: The resource class exists + rc, err := resourceclasses.Get(context.TODO(), client, name).Extract() + th.AssertNoErr(t, err) + th.AssertEquals(t, name, rc.Name) +} + +func TestResourceClassCreateByPostDuplicate(t *testing.T) { + // Resource classes were introduced in 1.2 + clients.SkipReleasesBelow(t, "stable/ocata") + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + client.Microversion = "1.2" + + name := strings.ToUpper(tools.RandomString("CUSTOM_", 8)) + createOpts := resourceclasses.CreateOpts{ + Name: name, + } + + // Act: Create a resource class using POST + err = resourceclasses.Create(context.TODO(), client, createOpts).ExtractErr() + th.AssertNoErr(t, err) + + // Act: Try to create the same resource class again + err = resourceclasses.Create(context.TODO(), client, createOpts).ExtractErr() + // Assert: The error is a conflict + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusConflict)) +} + +func TestResourceClassCreateByUpdateSuccess(t *testing.T) { + // Creating by Update (PUT) requires microversion 1.7 or later + clients.SkipReleasesBelow(t, "stable/pike") + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + client.Microversion = "1.7" + + name := strings.ToUpper(tools.RandomString("CUSTOM_", 8)) + + // Act: Create a resource class using PUT (Update) + err = resourceclasses.Update(context.TODO(), client, name).ExtractErr() + // No error, with 201 returned + th.AssertNoErr(t, err) + + // Act: Try to create the same resource class again + err = resourceclasses.Update(context.TODO(), client, name).ExtractErr() + // No error, with 204 returned + th.AssertNoErr(t, err) + + // Assert: The resource class exists + rc, err := resourceclasses.Get(context.TODO(), client, name).Extract() + th.AssertNoErr(t, err) + th.AssertEquals(t, name, rc.Name) +} + +func TestResourceClassCreateByUpdateNonCustomName(t *testing.T) { + // Creating by Update (PUT) requires microversion 1.7 or later + clients.SkipReleasesBelow(t, "stable/pike") + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + client.Microversion = "1.7" + + name := "CANNOT_CREATE_THIS" + + // Act: Try to create a resource class with a non-custom name using PUT (Update) + err = resourceclasses.Update(context.TODO(), client, name).ExtractErr() + // Assert: We get 400 + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) +} diff --git a/openstack/placement/v1/resourceclasses/doc.go b/openstack/placement/v1/resourceclasses/doc.go index 27f7c31ac8..53eae204c9 100644 --- a/openstack/placement/v1/resourceclasses/doc.go +++ b/openstack/placement/v1/resourceclasses/doc.go @@ -32,5 +32,27 @@ Example to Get a resource class } fmt.Printf("%+v\n", resourceClass) + +Example to Create a resource class using POST + + placementClient.Microversion = "1.2" + + createOpts := resourceclasses.CreateOpts{ + Name: "CUSTOM_RESOURCE_CLASS", + } + + err := resourceclasses.Create(context.TODO(), placementClient, createOpts).ExtractErr() + if err != nil { + panic(err) + } + +Example to ensure the existence of a resource class using PUT (idempotent creation) + + placementClient.Microversion = "1.7" + + err := resourceclasses.Update(context.TODO(), placementClient, "CUSTOM_RESOURCE_CLASS").ExtractErr() + if err != nil { + panic(err) + } */ package resourceclasses diff --git a/openstack/placement/v1/resourceclasses/requests.go b/openstack/placement/v1/resourceclasses/requests.go index d497224aaf..4fccd33c9c 100644 --- a/openstack/placement/v1/resourceclasses/requests.go +++ b/openstack/placement/v1/resourceclasses/requests.go @@ -22,3 +22,43 @@ func Get(ctx context.Context, client *gophercloud.ServiceClient, name string) (r _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return } + +// CreateOptsBuilder allows extensions to add additional parameters to +// the Create request. +type CreateOptsBuilder interface { + ToResourceClassCreateMap() (map[string]any, error) +} + +// CreateOpts represents the attributes of a new resource class. +type CreateOpts struct { + Name string `json:"name" required:"true"` +} + +// ToResourceClassCreateMap formats a CreateOpts into a create request. +func (opts CreateOpts) ToResourceClassCreateMap() (map[string]any, error) { + return gophercloud.BuildRequestBody(opts, "") +} + +// Create creates a new resource class. +func Create(ctx context.Context, client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { + b, err := opts.ToResourceClassCreateMap() + if err != nil { + r.Err = err + return + } + resp, err := client.Post(ctx, createURL(client), b, nil, &gophercloud.RequestOpts{ + OkCodes: []int{201}, + }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + +// Update ensures the existence of a custom resource class with the +// provided name (can be safely called multiple times). +func Update(ctx context.Context, client *gophercloud.ServiceClient, name string) (r UpdateResult) { + resp, err := client.Put(ctx, updateURL(client, name), nil, nil, &gophercloud.RequestOpts{ + OkCodes: []int{201, 204}, + }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} diff --git a/openstack/placement/v1/resourceclasses/results.go b/openstack/placement/v1/resourceclasses/results.go index 85ed0a4e80..cbd5501b9c 100644 --- a/openstack/placement/v1/resourceclasses/results.go +++ b/openstack/placement/v1/resourceclasses/results.go @@ -35,6 +35,18 @@ type GetResult struct { resourceClassResult } +// CreateResult is the response from a Create operation. Call its ExtractErr to +// determine if the request succeeded or failed. +type CreateResult struct { + gophercloud.ErrResult +} + +// UpdateResult is the response from an Update operation. Call its ExtractErr to +// determine if the request succeeded or failed. +type UpdateResult struct { + gophercloud.ErrResult +} + // ResourceClassesPage contains a single page of all resource classes from a List call. type ResourceClassesPage struct { pagination.SinglePageBase diff --git a/openstack/placement/v1/resourceclasses/testing/fixtures_test.go b/openstack/placement/v1/resourceclasses/testing/fixtures_test.go index b13e355244..7b0819cdef 100644 --- a/openstack/placement/v1/resourceclasses/testing/fixtures_test.go +++ b/openstack/placement/v1/resourceclasses/testing/fixtures_test.go @@ -12,6 +12,7 @@ import ( const PresentResourceClass = "CUSTOM_RESOURCE_CLASS" const AbsentResourceClass = "NON_EXISTENT_RC" +const NewResourceClass = "CUSTOM_NEW_RC" const ResourceClassGetResult = ` { @@ -116,3 +117,55 @@ func HandleGetResourceClassNotFound(t *testing.T, fakeServer th.FakeServer) { w.WriteHeader(http.StatusNotFound) }) } + +func HandleCreateResourceClassSuccess(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/resource_classes", + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.TestJSONRequest(t, r, `{"name": "CUSTOM_NEW_RC"}`) + + w.WriteHeader(http.StatusCreated) + }) +} + +func HandleCreateResourceClassConflict(t *testing.T, fakeServer th.FakeServer) { + // We simulate a conflict by trying to create a resource class that already exists. + fakeServer.Mux.HandleFunc("/resource_classes", + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.WriteHeader(http.StatusConflict) + }) +} + +func HandleUpdateResourceClassSuccess(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/resource_classes/"+NewResourceClass, + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "PUT") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.WriteHeader(http.StatusCreated) + }) +} + +func HandleUpdateResourceClassExists(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/resource_classes/"+PresentResourceClass, + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "PUT") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.WriteHeader(http.StatusNoContent) + }) +} + +func HandleUpdateResourceClassNonCustom(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/resource_classes/VCPU", + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "PUT") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.WriteHeader(http.StatusBadRequest) + }) +} diff --git a/openstack/placement/v1/resourceclasses/testing/requests_test.go b/openstack/placement/v1/resourceclasses/testing/requests_test.go index 4bb1f29f3c..e1a821f0de 100644 --- a/openstack/placement/v1/resourceclasses/testing/requests_test.go +++ b/openstack/placement/v1/resourceclasses/testing/requests_test.go @@ -45,3 +45,61 @@ func TestGetResourceClassNotFound(t *testing.T) { _, err := resourceclasses.Get(context.TODO(), client.ServiceClient(fakeServer), AbsentResourceClass).Extract() th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } + +func TestCreateResourceClassSuccess(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleCreateResourceClassSuccess(t, fakeServer) + + createOpts := resourceclasses.CreateOpts{ + Name: NewResourceClass, + } + + err := resourceclasses.Create(context.TODO(), client.ServiceClient(fakeServer), createOpts).ExtractErr() + th.AssertNoErr(t, err) +} + +func TestCreateResourceClassConflict(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleCreateResourceClassConflict(t, fakeServer) + + createOpts := resourceclasses.CreateOpts{ + Name: PresentResourceClass, + } + + err := resourceclasses.Create(context.TODO(), client.ServiceClient(fakeServer), createOpts).ExtractErr() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusConflict)) +} + +func TestUpdateResourceClassCreateSuccess(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleUpdateResourceClassSuccess(t, fakeServer) + + err := resourceclasses.Update(context.TODO(), client.ServiceClient(fakeServer), NewResourceClass).ExtractErr() + th.AssertNoErr(t, err) +} + +func TestUpdateResourceClassExists(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleUpdateResourceClassExists(t, fakeServer) + + err := resourceclasses.Update(context.TODO(), client.ServiceClient(fakeServer), PresentResourceClass).ExtractErr() + th.AssertNoErr(t, err) +} + +func TestUpdateResourceClassNonCustom(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleUpdateResourceClassNonCustom(t, fakeServer) + + err := resourceclasses.Update(context.TODO(), client.ServiceClient(fakeServer), "VCPU").ExtractErr() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) +} diff --git a/openstack/placement/v1/resourceclasses/urls.go b/openstack/placement/v1/resourceclasses/urls.go index 0fec96e30c..3dc3f82d19 100644 --- a/openstack/placement/v1/resourceclasses/urls.go +++ b/openstack/placement/v1/resourceclasses/urls.go @@ -8,6 +8,14 @@ func listURL(client *gophercloud.ServiceClient) string { return client.ServiceURL("resource_classes") } +func createURL(client *gophercloud.ServiceClient) string { + return client.ServiceURL("resource_classes") +} + func getURL(client *gophercloud.ServiceClient, name string) string { return client.ServiceURL("resource_classes", name) } + +func updateURL(client *gophercloud.ServiceClient, name string) string { + return client.ServiceURL("resource_classes", name) +} From 7ed59bb3448c1ab8d84a9e5cb66fda66c2b9b70a Mon Sep 17 00:00:00 2001 From: Dominik Danelski Date: Wed, 1 Apr 2026 20:12:12 +0200 Subject: [PATCH 353/429] Implement UPDATE operations on Placement resource providers inventories Related: #526 API reference: https://docs.openstack.org/api-ref/placement/#update-resource-provider-inventories https://docs.openstack.org/api-ref/placement/#update-resource-provider-inventory Code reference: https://opendev.org/openstack/placement/src/branch/stable/2026.1/placement/handlers/inventory.py#L257-L277 https://opendev.org/openstack/placement/src/branch/stable/2026.1/placement/handlers/inventory.py#L280-L307 Signed-off-by: Dominik Danelski --- .../placement/v1/resourceproviders_test.go | 147 ++++++++++++++++++ .../placement/v1/resourceproviders/doc.go | 51 ++++++ .../v1/resourceproviders/requests.go | 58 +++++++ .../placement/v1/resourceproviders/results.go | 18 +++ .../testing/fixtures_test.go | 132 ++++++++++++++++ .../testing/requests_test.go | 48 ++++++ .../placement/v1/resourceproviders/urls.go | 4 + 7 files changed, 458 insertions(+) diff --git a/internal/acceptance/openstack/placement/v1/resourceproviders_test.go b/internal/acceptance/openstack/placement/v1/resourceproviders_test.go index bd6c3f1fa4..b23cb318ae 100644 --- a/internal/acceptance/openstack/placement/v1/resourceproviders_test.go +++ b/internal/acceptance/openstack/placement/v1/resourceproviders_test.go @@ -4,14 +4,19 @@ package v1 import ( "context" + "net/http" "testing" + "github.com/gophercloud/gophercloud/v2" "github.com/gophercloud/gophercloud/v2/internal/acceptance/clients" "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/resourceproviders" th "github.com/gophercloud/gophercloud/v2/testhelper" ) +const InventoryResourceClass = "VCPU" +const NonExistentRPUUID = "00000000-0000-0000-0000-000000000000" + func TestResourceProviderList(t *testing.T) { clients.RequireAdmin(t) @@ -100,6 +105,148 @@ func TestResourceProviderInventories(t *testing.T) { tools.PrintResource(t, usage) } +func TestResourceProviderUpdateInventory(t *testing.T) { + clients.RequireAdmin(t) + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + resourceProvider, err := CreateResourceProvider(t, client) + th.AssertNoErr(t, err) + defer DeleteResourceProvider(t, client, resourceProvider.UUID) + + // Arrange: Get the current inventory to retrieve the generation + inventories, err := resourceproviders.GetInventories(context.TODO(), client, resourceProvider.UUID).Extract() + th.AssertNoErr(t, err) + + // Arrange: The resource class on this provider must exist first + seedOpts := resourceproviders.UpdateInventoriesOpts{ + ResourceProviderGeneration: inventories.ResourceProviderGeneration, + Inventories: map[string]resourceproviders.Inventory{ + InventoryResourceClass: { + AllocationRatio: 1.0, + MaxUnit: 4, + MinUnit: 1, + Reserved: 0, + StepSize: 1, + Total: 4, + }, + }, + } + + seededInventories, err := resourceproviders.UpdateInventories(context.TODO(), client, resourceProvider.UUID, seedOpts).Extract() + th.AssertNoErr(t, err) + + expectedInventory := resourceproviders.Inventory{ + AllocationRatio: 1.0, + MaxUnit: 8, + MinUnit: 1, + Reserved: 0, + StepSize: 1, + Total: 8, + } + + updateOpts := resourceproviders.UpdateInventoryOpts{ + ResourceProviderGeneration: seededInventories.ResourceProviderGeneration, + Inventory: expectedInventory, + } + + _, err = resourceproviders.UpdateInventory(context.TODO(), client, resourceProvider.UUID, InventoryResourceClass, updateOpts).Extract() + th.AssertNoErr(t, err) + + updatedInventories, err := resourceproviders.GetInventories(context.TODO(), client, resourceProvider.UUID).Extract() + th.AssertNoErr(t, err) + + actualInventory, ok := updatedInventories.Inventories[InventoryResourceClass] + th.AssertEquals(t, true, ok) + th.AssertDeepEquals(t, expectedInventory, actualInventory) +} + +func TestResourceProviderUpdateInventoryNotFound(t *testing.T) { + clients.RequireAdmin(t) + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + updateOpts := resourceproviders.UpdateInventoryOpts{ + ResourceProviderGeneration: 0, + Inventory: resourceproviders.Inventory{ + AllocationRatio: 1.0, + MaxUnit: 1, + MinUnit: 1, + Reserved: 0, + StepSize: 1, + Total: 1, + }, + } + + _, err = resourceproviders.UpdateInventory(context.TODO(), client, NonExistentRPUUID, InventoryResourceClass, updateOpts).Extract() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) +} + +func TestResourceProviderUpdateInventories(t *testing.T) { + clients.RequireAdmin(t) + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + resourceProvider, err := CreateResourceProvider(t, client) + th.AssertNoErr(t, err) + defer DeleteResourceProvider(t, client, resourceProvider.UUID) + + // Arrange: Get the current inventory to retrieve the generation + inventories, err := resourceproviders.GetInventories(context.TODO(), client, resourceProvider.UUID).Extract() + th.AssertNoErr(t, err) + + expectedInventories := map[string]resourceproviders.Inventory{ + "DISK_GB": { + AllocationRatio: 1.0, + MaxUnit: 100, + MinUnit: 1, + Reserved: 0, + StepSize: 1, + Total: 100, + }, + } + + updateOpts := resourceproviders.UpdateInventoriesOpts{ + ResourceProviderGeneration: inventories.ResourceProviderGeneration, + Inventories: expectedInventories, + } + + _, err = resourceproviders.UpdateInventories(context.TODO(), client, resourceProvider.UUID, updateOpts).Extract() + th.AssertNoErr(t, err) + + updatedInventories, err := resourceproviders.GetInventories(context.TODO(), client, resourceProvider.UUID).Extract() + th.AssertNoErr(t, err) + + th.AssertDeepEquals(t, expectedInventories, updatedInventories.Inventories) +} + +func TestResourceProviderUpdateInventoriesNotFound(t *testing.T) { + clients.RequireAdmin(t) + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + updateOpts := resourceproviders.UpdateInventoriesOpts{ + ResourceProviderGeneration: 0, + Inventories: map[string]resourceproviders.Inventory{ + InventoryResourceClass: { + AllocationRatio: 1.0, + MaxUnit: 1, + MinUnit: 1, + Reserved: 0, + StepSize: 1, + Total: 1, + }, + }, + } + + _, err = resourceproviders.UpdateInventories(context.TODO(), client, NonExistentRPUUID, updateOpts).Extract() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) +} + func TestResourceProviderTraits(t *testing.T) { clients.RequireAdmin(t) diff --git a/openstack/placement/v1/resourceproviders/doc.go b/openstack/placement/v1/resourceproviders/doc.go index d659558f15..729222ab9b 100644 --- a/openstack/placement/v1/resourceproviders/doc.go +++ b/openstack/placement/v1/resourceproviders/doc.go @@ -75,6 +75,57 @@ Example to get resource providers inventories panic(err) } +Example to update (replace) all resource provider inventories + + inventories, err := resourceproviders.GetInventories(context.TODO(), placementClient, resourceProviderID).Extract() + if err != nil { + panic(err) + } + + updateInventoriesOpts := resourceproviders.UpdateInventoriesOpts{ + ResourceProviderGeneration: inventories.ResourceProviderGeneration, + Inventories: map[string]resourceproviders.Inventory{ + "VCPU": { + Total: 4, + Reserved: 0, + MinUnit: 1, + MaxUnit: 4, + StepSize: 1, + AllocationRatio: 16.0, + }, + }, + } + + rp, err = resourceproviders.UpdateInventories(context.TODO(), placementClient, resourceProviderID, updateInventoriesOpts).Extract() + if err != nil { + panic(err) + } + +Example to update one existing resource provider inventory + + inventories, err := resourceproviders.GetInventories(context.TODO(), placementClient, resourceProviderID).Extract() + if err != nil { + panic(err) + } + + // UpdateInventory updates an existing resource class inventory. + updateInventoryOpts := resourceproviders.UpdateInventoryOpts{ + ResourceProviderGeneration: inventories.ResourceProviderGeneration, + Inventory: resourceproviders.Inventory{ + Total: 4, + Reserved: 0, + MinUnit: 1, + MaxUnit: 4, + StepSize: 1, + AllocationRatio: 16.0, + }, + } + + rpInventory, err := resourceproviders.UpdateInventory(context.TODO(), placementClient, resourceProviderID, "VCPU", updateInventoryOpts).Extract() + if err != nil { + panic(err) + } + Example to get resource providers traits rp, err := resourceproviders.GetTraits(context.TODO(), placementClient, resourceProviderID).Extract() diff --git a/openstack/placement/v1/resourceproviders/requests.go b/openstack/placement/v1/resourceproviders/requests.go index f0dfa9d66f..1ef7690ad1 100644 --- a/openstack/placement/v1/resourceproviders/requests.go +++ b/openstack/placement/v1/resourceproviders/requests.go @@ -164,6 +164,64 @@ func GetInventories(ctx context.Context, client *gophercloud.ServiceClient, reso return } +// UpdateInventoriesOptsBuilder allows extensions to add additional parameters to the +// UpdateInventories request. +type UpdateInventoriesOptsBuilder interface { + ToResourceProviderUpdateInventoriesMap() (map[string]any, error) +} + +// UpdateInventoriesOpts represents options used to update all inventories of a resource provider. +type UpdateInventoriesOpts = ResourceProviderInventories + +// ToResourceProviderUpdateInventoriesMap constructs a request body from UpdateInventoriesOpts. +func (opts UpdateInventoriesOpts) ToResourceProviderUpdateInventoriesMap() (map[string]any, error) { + return gophercloud.BuildRequestBody(opts, "") +} + +// UpdateInventories updates all inventories of a resource provider. +func UpdateInventories(ctx context.Context, client *gophercloud.ServiceClient, resourceProviderID string, opts UpdateInventoriesOptsBuilder) (r GetInventoriesResult) { + b, err := opts.ToResourceProviderUpdateInventoriesMap() + if err != nil { + r.Err = err + return + } + + resp, err := client.Put(ctx, getResourceProviderInventoriesURL(client, resourceProviderID), b, &r.Body, &gophercloud.RequestOpts{ + OkCodes: []int{200}, + }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + +// UpdateInventoryOptsBuilder allows extensions to add additional parameters to the +// UpdateInventory request. +type UpdateInventoryOptsBuilder interface { + ToResourceProviderUpdateInventoryMap() (map[string]any, error) +} + +// UpdateInventoryOpts represents options used to update one inventory of a resource provider. +type UpdateInventoryOpts = ResourceProviderInventory + +// ToResourceProviderUpdateInventoryMap constructs a request body from UpdateInventoryOpts. +func (opts UpdateInventoryOpts) ToResourceProviderUpdateInventoryMap() (map[string]any, error) { + return gophercloud.BuildRequestBody(opts, "") +} + +// UpdateInventory updates one inventory of a resource provider. +func UpdateInventory(ctx context.Context, client *gophercloud.ServiceClient, resourceProviderID, resourceClass string, opts UpdateInventoryOptsBuilder) (r UpdateInventoryResult) { + b, err := opts.ToResourceProviderUpdateInventoryMap() + if err != nil { + r.Err = err + return + } + + resp, err := client.Put(ctx, updateResourceProviderInventoryURL(client, resourceProviderID, resourceClass), b, &r.Body, &gophercloud.RequestOpts{ + OkCodes: []int{200}, + }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + func GetAllocations(ctx context.Context, client *gophercloud.ServiceClient, resourceProviderID string) (r GetAllocationsResult) { resp, err := client.Get(ctx, getResourceProviderAllocationsURL(client, resourceProviderID), &r.Body, nil) _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) diff --git a/openstack/placement/v1/resourceproviders/results.go b/openstack/placement/v1/resourceproviders/results.go index 19b71103e1..4c00bad016 100644 --- a/openstack/placement/v1/resourceproviders/results.go +++ b/openstack/placement/v1/resourceproviders/results.go @@ -56,6 +56,11 @@ type ResourceProviderInventories struct { Inventories map[string]Inventory `json:"inventories"` } +type ResourceProviderInventory struct { + ResourceProviderGeneration int `json:"resource_provider_generation"` + Inventory +} + type ResourceProviderAllocations struct { ResourceProviderGeneration int `json:"resource_provider_generation"` Allocations map[string]Allocation `json:"allocations"` @@ -153,6 +158,19 @@ func (r GetInventoriesResult) Extract() (*ResourceProviderInventories, error) { return &s, err } +// UpdateInventoryResult is the response of an Update inventory operation. Call its Extract method +// to interpret it as a ResourceProviderInventory. +type UpdateInventoryResult struct { + gophercloud.Result +} + +// Extract interprets a UpdateInventoryResult as a ResourceProviderInventory. +func (r UpdateInventoryResult) Extract() (*ResourceProviderInventory, error) { + var s ResourceProviderInventory + err := r.ExtractInto(&s) + return &s, err +} + // GetAllocationsResult is the response of a Get allocations operations. Call its Extract method // to interpret it as a ResourceProviderAllocations. type GetAllocationsResult struct { diff --git a/openstack/placement/v1/resourceproviders/testing/fixtures_test.go b/openstack/placement/v1/resourceproviders/testing/fixtures_test.go index 6ac4b8ca73..f50a7f4547 100644 --- a/openstack/placement/v1/resourceproviders/testing/fixtures_test.go +++ b/openstack/placement/v1/resourceproviders/testing/fixtures_test.go @@ -12,6 +12,8 @@ import ( ) const ResourceProviderTestID = "99c09379-6e52-4ef8-9a95-b9ce6f68452e" +const PresentInventoryResourceClass = "VCPU" +const NonExistentRPID = "00000000-0000-0000-0000-000000000000" const ResourceProvidersBody = ` { @@ -128,6 +130,62 @@ const InventoriesBody = ` } ` +const UpdateInventoriesRequest = ` +{ + "resource_provider_generation": 7, + "inventories": { + "DISK_GB": { + "allocation_ratio": 1.0, + "max_unit": 35, + "min_unit": 1, + "reserved": 0, + "step_size": 1, + "total": 35 + }, + "MEMORY_MB": { + "allocation_ratio": 1.5, + "max_unit": 5825, + "min_unit": 1, + "reserved": 512, + "step_size": 1, + "total": 5825 + }, + "VCPU": { + "allocation_ratio": 16.0, + "max_unit": 4, + "min_unit": 1, + "reserved": 0, + "step_size": 1, + "total": 4 + } + } +} +` + +const InventoryBody = ` +{ + "resource_provider_generation": 7, + "allocation_ratio": 16.0, + "max_unit": 4, + "min_unit": 1, + "reserved": 0, + "step_size": 1, + "total": 4 +} +` + +const UpdateInventoryRequest = ` +{ + "resource_provider_generation": 7, + "allocation_ratio": 16.0, + "max_unit": 4, + "min_unit": 1, + "reserved": 0, + "step_size": 1, + "total": 4 +} +` + const AllocationsBody = ` { "allocations": { @@ -236,6 +294,18 @@ var ExpectedInventories = resourceproviders.ResourceProviderInventories{ }, } +var ExpectedInventory = resourceproviders.ResourceProviderInventory{ + ResourceProviderGeneration: 7, + Inventory: resourceproviders.Inventory{ + AllocationRatio: 16.0, + MaxUnit: 4, + MinUnit: 1, + Reserved: 0, + StepSize: 1, + Total: 4, + }, +} + var ExpectedAllocations = resourceproviders.ResourceProviderAllocations{ ResourceProviderGeneration: 12, Allocations: map[string]resourceproviders.Allocation{ @@ -358,6 +428,68 @@ func HandleResourceProviderGetInventories(t *testing.T, fakeServer th.FakeServer }) } +func HandleResourceProviderPutInventories(t *testing.T, fakeServer th.FakeServer) { + inventoriesTestURL := fmt.Sprintf("/resource_providers/%s/inventories", ResourceProviderTestID) + + fakeServer.Mux.HandleFunc(inventoriesTestURL, + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "PUT") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestJSONRequest(t, r, UpdateInventoriesRequest) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, InventoriesBody) + }) +} + +func HandleResourceProviderPutInventoriesNotFound(t *testing.T, fakeServer th.FakeServer) { + inventoriesNotFoundURL := fmt.Sprintf("/resource_providers/%s/inventories", NonExistentRPID) + + fakeServer.Mux.HandleFunc(inventoriesNotFoundURL, + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "PUT") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusNotFound) + fmt.Fprint(w, `{"errors":[{"status":404,"title":"Not Found"}]}`) + }) +} + +func HandleResourceProviderPutInventory(t *testing.T, fakeServer th.FakeServer) { + inventoryTestURL := fmt.Sprintf("/resource_providers/%s/inventories/%s", ResourceProviderTestID, PresentInventoryResourceClass) + + fakeServer.Mux.HandleFunc(inventoryTestURL, + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "PUT") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestJSONRequest(t, r, UpdateInventoryRequest) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, InventoryBody) + }) +} + +func HandleResourceProviderPutInventoryNotFound(t *testing.T, fakeServer th.FakeServer) { + inventoryNotFoundURL := fmt.Sprintf("/resource_providers/%s/inventories/%s", NonExistentRPID, PresentInventoryResourceClass) + + fakeServer.Mux.HandleFunc(inventoryNotFoundURL, + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "PUT") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusNotFound) + fmt.Fprint(w, `{"errors":[{"status":404,"title":"Not Found"}]}`) + }) +} + func HandleResourceProviderGetAllocations(t *testing.T, fakeServer th.FakeServer) { allocationsTestUrl := fmt.Sprintf("/resource_providers/%s/allocations", ResourceProviderTestID) diff --git a/openstack/placement/v1/resourceproviders/testing/requests_test.go b/openstack/placement/v1/resourceproviders/testing/requests_test.go index 4633c81136..67546d1930 100644 --- a/openstack/placement/v1/resourceproviders/testing/requests_test.go +++ b/openstack/placement/v1/resourceproviders/testing/requests_test.go @@ -2,8 +2,10 @@ package testing import ( "context" + "net/http" "testing" + "github.com/gophercloud/gophercloud/v2" "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/resourceproviders" "github.com/gophercloud/gophercloud/v2/pagination" @@ -124,6 +126,52 @@ func TestGetResourceProvidersInventories(t *testing.T) { th.AssertDeepEquals(t, ExpectedInventories, *actual) } +func TestUpdateResourceProvidersInventories(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleResourceProviderPutInventories(t, fakeServer) + + opts := resourceproviders.UpdateInventoriesOpts(ExpectedInventories) + actual, err := resourceproviders.UpdateInventories(context.TODO(), client.ServiceClient(fakeServer), ResourceProviderTestID, opts).Extract() + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedInventories, *actual) +} + +func TestUpdateResourceProvidersInventoriesNotFound(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleResourceProviderPutInventoriesNotFound(t, fakeServer) + + opts := resourceproviders.UpdateInventoriesOpts(ExpectedInventories) + _, err := resourceproviders.UpdateInventories(context.TODO(), client.ServiceClient(fakeServer), NonExistentRPID, opts).Extract() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) +} + +func TestUpdateResourceProviderInventory(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleResourceProviderPutInventory(t, fakeServer) + + opts := resourceproviders.UpdateInventoryOpts(ExpectedInventory) + actual, err := resourceproviders.UpdateInventory(context.TODO(), client.ServiceClient(fakeServer), ResourceProviderTestID, PresentInventoryResourceClass, opts).Extract() + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedInventory, *actual) +} + +func TestUpdateResourceProviderInventoryNotFound(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleResourceProviderPutInventoryNotFound(t, fakeServer) + + opts := resourceproviders.UpdateInventoryOpts(ExpectedInventory) + _, err := resourceproviders.UpdateInventory(context.TODO(), client.ServiceClient(fakeServer), NonExistentRPID, PresentInventoryResourceClass, opts).Extract() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) +} + func TestGetResourceProvidersAllocations(t *testing.T) { fakeServer := th.SetupHTTP() defer fakeServer.Teardown() diff --git a/openstack/placement/v1/resourceproviders/urls.go b/openstack/placement/v1/resourceproviders/urls.go index 037149b684..5fe326e4bc 100644 --- a/openstack/placement/v1/resourceproviders/urls.go +++ b/openstack/placement/v1/resourceproviders/urls.go @@ -30,6 +30,10 @@ func getResourceProviderInventoriesURL(client *gophercloud.ServiceClient, resour return client.ServiceURL(apiName, resourceProviderID, "inventories") } +func updateResourceProviderInventoryURL(client *gophercloud.ServiceClient, resourceProviderID, resourceClass string) string { + return client.ServiceURL(apiName, resourceProviderID, "inventories", resourceClass) +} + func getResourceProviderAllocationsURL(client *gophercloud.ServiceClient, resourceProviderID string) string { return client.ServiceURL(apiName, resourceProviderID, "allocations") } From 6b55a24bcb5a51d908f2db3ba5a30269169ead03 Mon Sep 17 00:00:00 2001 From: Dominik Danelski Date: Wed, 1 Apr 2026 18:16:46 +0200 Subject: [PATCH 354/429] Implement resource providers inventory GET Related #526 API reference: https://docs.openstack.org/api-ref/placement/#show-resource-provider-inventory Code reference: https://opendev.org/openstack/placement/src/branch/stable/2026.1/placement/handlers/inventory.py#L280-L307 Signed-off-by: Dominik Danelski --- .../placement/v1/resourceproviders_test.go | 67 +++++++++++++++++++ .../placement/v1/resourceproviders/doc.go | 7 ++ .../v1/resourceproviders/requests.go | 6 ++ .../placement/v1/resourceproviders/results.go | 13 ++++ .../testing/fixtures_test.go | 27 ++++++++ .../testing/requests_test.go | 21 ++++++ .../placement/v1/resourceproviders/urls.go | 4 ++ 7 files changed, 145 insertions(+) diff --git a/internal/acceptance/openstack/placement/v1/resourceproviders_test.go b/internal/acceptance/openstack/placement/v1/resourceproviders_test.go index b23cb318ae..c1aa52ea94 100644 --- a/internal/acceptance/openstack/placement/v1/resourceproviders_test.go +++ b/internal/acceptance/openstack/placement/v1/resourceproviders_test.go @@ -15,6 +15,7 @@ import ( ) const InventoryResourceClass = "VCPU" +const MissingInventoryResourceClass = "NO_SUCH_CLASS" const NonExistentRPUUID = "00000000-0000-0000-0000-000000000000" func TestResourceProviderList(t *testing.T) { @@ -105,6 +106,72 @@ func TestResourceProviderInventories(t *testing.T) { tools.PrintResource(t, usage) } +func TestResourceProviderInventory(t *testing.T) { + clients.RequireAdmin(t) + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + resourceProvider, err := CreateResourceProvider(t, client) + th.AssertNoErr(t, err) + defer DeleteResourceProvider(t, client, resourceProvider.UUID) + + inventories, err := resourceproviders.GetInventories(context.TODO(), client, resourceProvider.UUID).Extract() + th.AssertNoErr(t, err) + + seededInventories, err := resourceproviders.UpdateInventories(context.TODO(), client, resourceProvider.UUID, resourceproviders.UpdateInventoriesOpts{ + ResourceProviderGeneration: inventories.ResourceProviderGeneration, + Inventories: map[string]resourceproviders.Inventory{ + InventoryResourceClass: { + AllocationRatio: 1.0, + MaxUnit: 4, + MinUnit: 1, + Reserved: 0, + StepSize: 1, + Total: 4, + }, + }, + }).Extract() + th.AssertNoErr(t, err) + + inventory, err := resourceproviders.GetInventory(context.TODO(), client, resourceProvider.UUID, InventoryResourceClass).Extract() + th.AssertNoErr(t, err) + th.AssertEquals(t, seededInventories.ResourceProviderGeneration, inventory.ResourceProviderGeneration) + th.AssertDeepEquals(t, seededInventories.Inventories[InventoryResourceClass], inventory.Inventory) +} + +func TestResourceProviderInventoryNotFound(t *testing.T) { + clients.RequireAdmin(t) + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + resourceProvider, err := CreateResourceProvider(t, client) + th.AssertNoErr(t, err) + defer DeleteResourceProvider(t, client, resourceProvider.UUID) + + inventories, err := resourceproviders.GetInventories(context.TODO(), client, resourceProvider.UUID).Extract() + th.AssertNoErr(t, err) + + _, err = resourceproviders.UpdateInventories(context.TODO(), client, resourceProvider.UUID, resourceproviders.UpdateInventoriesOpts{ + ResourceProviderGeneration: inventories.ResourceProviderGeneration, + Inventories: map[string]resourceproviders.Inventory{ + InventoryResourceClass: { + AllocationRatio: 1.0, + MaxUnit: 4, + MinUnit: 1, + Reserved: 0, + StepSize: 1, + Total: 4, + }, + }, + }).Extract() + th.AssertNoErr(t, err) + + _, err = resourceproviders.GetInventory(context.TODO(), client, resourceProvider.UUID, MissingInventoryResourceClass).Extract() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) +} + func TestResourceProviderUpdateInventory(t *testing.T) { clients.RequireAdmin(t) diff --git a/openstack/placement/v1/resourceproviders/doc.go b/openstack/placement/v1/resourceproviders/doc.go index 729222ab9b..4a1270794a 100644 --- a/openstack/placement/v1/resourceproviders/doc.go +++ b/openstack/placement/v1/resourceproviders/doc.go @@ -75,6 +75,13 @@ Example to get resource providers inventories panic(err) } +Example to get one resource provider inventory + + rpInventory, err := resourceproviders.GetInventory(context.TODO(), placementClient, resourceProviderID, "VCPU").Extract() + if err != nil { + panic(err) + } + Example to update (replace) all resource provider inventories inventories, err := resourceproviders.GetInventories(context.TODO(), placementClient, resourceProviderID).Extract() diff --git a/openstack/placement/v1/resourceproviders/requests.go b/openstack/placement/v1/resourceproviders/requests.go index 1ef7690ad1..2985d63794 100644 --- a/openstack/placement/v1/resourceproviders/requests.go +++ b/openstack/placement/v1/resourceproviders/requests.go @@ -164,6 +164,12 @@ func GetInventories(ctx context.Context, client *gophercloud.ServiceClient, reso return } +func GetInventory(ctx context.Context, client *gophercloud.ServiceClient, resourceProviderID, resourceClass string) (r GetInventoryResult) { + resp, err := client.Get(ctx, getResourceProviderInventoryURL(client, resourceProviderID, resourceClass), &r.Body, nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + // UpdateInventoriesOptsBuilder allows extensions to add additional parameters to the // UpdateInventories request. type UpdateInventoriesOptsBuilder interface { diff --git a/openstack/placement/v1/resourceproviders/results.go b/openstack/placement/v1/resourceproviders/results.go index 4c00bad016..7f67c39819 100644 --- a/openstack/placement/v1/resourceproviders/results.go +++ b/openstack/placement/v1/resourceproviders/results.go @@ -158,6 +158,19 @@ func (r GetInventoriesResult) Extract() (*ResourceProviderInventories, error) { return &s, err } +// GetInventoryResult is the response of a Get inventory operation. Call its Extract method +// to interpret it as a ResourceProviderInventory. +type GetInventoryResult struct { + gophercloud.Result +} + +// Extract interprets a GetInventoryResult as a ResourceProviderInventory. +func (r GetInventoryResult) Extract() (*ResourceProviderInventory, error) { + var s ResourceProviderInventory + err := r.ExtractInto(&s) + return &s, err +} + // UpdateInventoryResult is the response of an Update inventory operation. Call its Extract method // to interpret it as a ResourceProviderInventory. type UpdateInventoryResult struct { diff --git a/openstack/placement/v1/resourceproviders/testing/fixtures_test.go b/openstack/placement/v1/resourceproviders/testing/fixtures_test.go index f50a7f4547..d904e1e98c 100644 --- a/openstack/placement/v1/resourceproviders/testing/fixtures_test.go +++ b/openstack/placement/v1/resourceproviders/testing/fixtures_test.go @@ -13,6 +13,7 @@ import ( const ResourceProviderTestID = "99c09379-6e52-4ef8-9a95-b9ce6f68452e" const PresentInventoryResourceClass = "VCPU" +const MissingInventoryResourceClass = "NO_SUCH_CLASS" const NonExistentRPID = "00000000-0000-0000-0000-000000000000" const ResourceProvidersBody = ` @@ -428,6 +429,32 @@ func HandleResourceProviderGetInventories(t *testing.T, fakeServer th.FakeServer }) } +func HandleResourceProviderGetInventory(t *testing.T, fakeServer th.FakeServer) { + inventoryTestURL := fmt.Sprintf("/resource_providers/%s/inventories/%s", ResourceProviderTestID, PresentInventoryResourceClass) + + fakeServer.Mux.HandleFunc(inventoryTestURL, + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, InventoryBody) + }) +} + +func HandleResourceProviderGetInventoryNotFound(t *testing.T, fakeServer th.FakeServer) { + inventoryNotFoundURL := fmt.Sprintf("/resource_providers/%s/inventories/%s", ResourceProviderTestID, MissingInventoryResourceClass) + + fakeServer.Mux.HandleFunc(inventoryNotFoundURL, + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + w.WriteHeader(http.StatusNotFound) + }) +} + func HandleResourceProviderPutInventories(t *testing.T, fakeServer th.FakeServer) { inventoriesTestURL := fmt.Sprintf("/resource_providers/%s/inventories", ResourceProviderTestID) diff --git a/openstack/placement/v1/resourceproviders/testing/requests_test.go b/openstack/placement/v1/resourceproviders/testing/requests_test.go index 67546d1930..5b12d37c89 100644 --- a/openstack/placement/v1/resourceproviders/testing/requests_test.go +++ b/openstack/placement/v1/resourceproviders/testing/requests_test.go @@ -126,6 +126,27 @@ func TestGetResourceProvidersInventories(t *testing.T) { th.AssertDeepEquals(t, ExpectedInventories, *actual) } +func TestGetResourceProviderInventory(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleResourceProviderGetInventory(t, fakeServer) + + actual, err := resourceproviders.GetInventory(context.TODO(), client.ServiceClient(fakeServer), ResourceProviderTestID, PresentInventoryResourceClass).Extract() + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedInventory, *actual) +} + +func TestGetResourceProviderInventoryNotFound(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleResourceProviderGetInventoryNotFound(t, fakeServer) + + _, err := resourceproviders.GetInventory(context.TODO(), client.ServiceClient(fakeServer), ResourceProviderTestID, MissingInventoryResourceClass).Extract() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) +} + func TestUpdateResourceProvidersInventories(t *testing.T) { fakeServer := th.SetupHTTP() defer fakeServer.Teardown() diff --git a/openstack/placement/v1/resourceproviders/urls.go b/openstack/placement/v1/resourceproviders/urls.go index 5fe326e4bc..61d6e1e811 100644 --- a/openstack/placement/v1/resourceproviders/urls.go +++ b/openstack/placement/v1/resourceproviders/urls.go @@ -30,6 +30,10 @@ func getResourceProviderInventoriesURL(client *gophercloud.ServiceClient, resour return client.ServiceURL(apiName, resourceProviderID, "inventories") } +func getResourceProviderInventoryURL(client *gophercloud.ServiceClient, resourceProviderID, resourceClass string) string { + return client.ServiceURL(apiName, resourceProviderID, "inventories", resourceClass) +} + func updateResourceProviderInventoryURL(client *gophercloud.ServiceClient, resourceProviderID, resourceClass string) string { return client.ServiceURL(apiName, resourceProviderID, "inventories", resourceClass) } From b4771fb6d359c492668161414125e1cd8e407184 Mon Sep 17 00:00:00 2001 From: Dominik Danelski Date: Thu, 2 Apr 2026 11:31:47 +0200 Subject: [PATCH 355/429] Implement resource providers inventory DELETE API reference: https://docs.openstack.org/api-ref/placement/#delete-resource-provider-inventories https://docs.openstack.org/api-ref/placement/#delete-resource-provider-inventory Code reference: https://opendev.org/openstack/placement/src/branch/stable/2026.1/placement/handlers/inventory.py#L377-L410 https://opendev.org/openstack/placement/src/branch/stable/2026.1/placement/handlers/inventory.py#L222-L254 Signed-off-by: Dominik Danelski --- .../placement/v1/resourceproviders_test.go | 102 ++++++++++++++++++ .../placement/v1/resourceproviders/doc.go | 16 +++ .../v1/resourceproviders/requests.go | 14 +++ .../testing/fixtures_test.go | 52 +++++++++ .../testing/requests_test.go | 40 +++++++ .../placement/v1/resourceproviders/urls.go | 8 ++ 6 files changed, 232 insertions(+) diff --git a/internal/acceptance/openstack/placement/v1/resourceproviders_test.go b/internal/acceptance/openstack/placement/v1/resourceproviders_test.go index c1aa52ea94..ecad86b4d9 100644 --- a/internal/acceptance/openstack/placement/v1/resourceproviders_test.go +++ b/internal/acceptance/openstack/placement/v1/resourceproviders_test.go @@ -251,6 +251,108 @@ func TestResourceProviderUpdateInventoryNotFound(t *testing.T) { th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } +func TestResourceProviderDeleteInventorySuccess(t *testing.T) { + clients.RequireAdmin(t) + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + resourceProvider, err := CreateResourceProvider(t, client) + th.AssertNoErr(t, err) + defer DeleteResourceProvider(t, client, resourceProvider.UUID) + + // Arrange: Get the current inventory to retrieve the generation + inventories, err := resourceproviders.GetInventories(context.TODO(), client, resourceProvider.UUID).Extract() + th.AssertNoErr(t, err) + + _, err = resourceproviders.UpdateInventories(context.TODO(), client, resourceProvider.UUID, resourceproviders.UpdateInventoriesOpts{ + ResourceProviderGeneration: inventories.ResourceProviderGeneration, + Inventories: map[string]resourceproviders.Inventory{ + InventoryResourceClass: { + AllocationRatio: 1.0, + MaxUnit: 4, + MinUnit: 1, + Reserved: 0, + StepSize: 1, + Total: 4, + }, + }, + }).Extract() + th.AssertNoErr(t, err) + + err = resourceproviders.DeleteInventory(context.TODO(), client, resourceProvider.UUID, InventoryResourceClass).ExtractErr() + th.AssertNoErr(t, err) + + // Assert: The inventory should no longer be found + updatedInventories, err := resourceproviders.GetInventories(context.TODO(), client, resourceProvider.UUID).Extract() + th.AssertNoErr(t, err) + + _, found := updatedInventories.Inventories[InventoryResourceClass] + th.AssertEquals(t, false, found) +} + +func TestResourceProviderDeleteInventoryNotFound(t *testing.T) { + clients.RequireAdmin(t) + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + resourceProvider, err := CreateResourceProvider(t, client) + th.AssertNoErr(t, err) + defer DeleteResourceProvider(t, client, resourceProvider.UUID) + + err = resourceproviders.DeleteInventory(context.TODO(), client, resourceProvider.UUID, MissingInventoryResourceClass).ExtractErr() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) +} + +func TestResourceProviderDeleteInventoriesSuccess(t *testing.T) { + clients.RequireAdmin(t) + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + resourceProvider, err := CreateResourceProvider(t, client) + th.AssertNoErr(t, err) + defer DeleteResourceProvider(t, client, resourceProvider.UUID) + + inventories, err := resourceproviders.GetInventories(context.TODO(), client, resourceProvider.UUID).Extract() + th.AssertNoErr(t, err) + + _, err = resourceproviders.UpdateInventories(context.TODO(), client, resourceProvider.UUID, resourceproviders.UpdateInventoriesOpts{ + ResourceProviderGeneration: inventories.ResourceProviderGeneration, + Inventories: map[string]resourceproviders.Inventory{ + InventoryResourceClass: { + AllocationRatio: 1.0, + MaxUnit: 4, + MinUnit: 1, + Reserved: 0, + StepSize: 1, + Total: 4, + }, + "MEMORY_MB": { + AllocationRatio: 1.0, + MaxUnit: 1024, + MinUnit: 1, + Reserved: 0, + StepSize: 1, + Total: 1024, + }, + }, + }).Extract() + th.AssertNoErr(t, err) + + seededInventories, err := resourceproviders.GetInventories(context.TODO(), client, resourceProvider.UUID).Extract() + th.AssertNoErr(t, err) + th.AssertEquals(t, 2, len(seededInventories.Inventories)) + + err = resourceproviders.DeleteInventories(context.TODO(), client, resourceProvider.UUID).ExtractErr() + th.AssertNoErr(t, err) + + updatedInventories, err := resourceproviders.GetInventories(context.TODO(), client, resourceProvider.UUID).Extract() + th.AssertNoErr(t, err) + th.AssertEquals(t, 0, len(updatedInventories.Inventories)) +} + func TestResourceProviderUpdateInventories(t *testing.T) { clients.RequireAdmin(t) diff --git a/openstack/placement/v1/resourceproviders/doc.go b/openstack/placement/v1/resourceproviders/doc.go index 4a1270794a..d47be9310c 100644 --- a/openstack/placement/v1/resourceproviders/doc.go +++ b/openstack/placement/v1/resourceproviders/doc.go @@ -133,6 +133,22 @@ Example to update one existing resource provider inventory panic(err) } +Example to delete one existing resource provider inventory +Since this request does not accept the resource provider generation, it is not safe to use when multiple threads are managing inventories for a single provider. In such situations use UpdateInventories with the empty inventory. + + err = resourceproviders.DeleteInventory(context.TODO(), placementClient, resourceProviderID, "VCPU").ExtractErr() + if err != nil { + panic(err) + } + +Example to delete all resource provider inventories +Since this request does not accept the resource provider generation, it is not safe to use when multiple threads are managing inventories for a single provider. In such situations use UpdateInventories with an empty inventory map. + + err = resourceproviders.DeleteInventories(context.TODO(), placementClient, resourceProviderID).ExtractErr() + if err != nil { + panic(err) + } + Example to get resource providers traits rp, err := resourceproviders.GetTraits(context.TODO(), placementClient, resourceProviderID).Extract() diff --git a/openstack/placement/v1/resourceproviders/requests.go b/openstack/placement/v1/resourceproviders/requests.go index 2985d63794..a1eedeb28d 100644 --- a/openstack/placement/v1/resourceproviders/requests.go +++ b/openstack/placement/v1/resourceproviders/requests.go @@ -199,6 +199,13 @@ func UpdateInventories(ctx context.Context, client *gophercloud.ServiceClient, r return } +// DeleteInventories deletes all inventories from a resource provider. +func DeleteInventories(ctx context.Context, client *gophercloud.ServiceClient, resourceProviderID string) (r DeleteResult) { + resp, err := client.Delete(ctx, deleteResourceProviderInventoriesURL(client, resourceProviderID), &gophercloud.RequestOpts{OkCodes: []int{204}}) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + // UpdateInventoryOptsBuilder allows extensions to add additional parameters to the // UpdateInventory request. type UpdateInventoryOptsBuilder interface { @@ -228,6 +235,13 @@ func UpdateInventory(ctx context.Context, client *gophercloud.ServiceClient, res return } +// DeleteInventory deletes one inventory from a resource provider. +func DeleteInventory(ctx context.Context, client *gophercloud.ServiceClient, resourceProviderID, resourceClass string) (r DeleteResult) { + resp, err := client.Delete(ctx, deleteResourceProviderInventoryURL(client, resourceProviderID, resourceClass), &gophercloud.RequestOpts{OkCodes: []int{204}}) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + func GetAllocations(ctx context.Context, client *gophercloud.ServiceClient, resourceProviderID string) (r GetAllocationsResult) { resp, err := client.Get(ctx, getResourceProviderAllocationsURL(client, resourceProviderID), &r.Body, nil) _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) diff --git a/openstack/placement/v1/resourceproviders/testing/fixtures_test.go b/openstack/placement/v1/resourceproviders/testing/fixtures_test.go index d904e1e98c..7a0b176114 100644 --- a/openstack/placement/v1/resourceproviders/testing/fixtures_test.go +++ b/openstack/placement/v1/resourceproviders/testing/fixtures_test.go @@ -517,6 +517,58 @@ func HandleResourceProviderPutInventoryNotFound(t *testing.T, fakeServer th.Fake }) } +func HandleResourceProviderDeleteInventorySuccess(t *testing.T, fakeServer th.FakeServer) { + inventoryDeleteURL := fmt.Sprintf("/resource_providers/%s/inventories/%s", ResourceProviderTestID, PresentInventoryResourceClass) + + fakeServer.Mux.HandleFunc(inventoryDeleteURL, + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "DELETE") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.AssertEquals(t, "", r.URL.RawQuery) + w.WriteHeader(http.StatusNoContent) + }) +} + +func HandleResourceProviderDeleteInventoryInUse(t *testing.T, fakeServer th.FakeServer) { + inventoryDeleteURL := fmt.Sprintf("/resource_providers/%s/inventories/%s", ResourceProviderTestID, PresentInventoryResourceClass) + + fakeServer.Mux.HandleFunc(inventoryDeleteURL, + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "DELETE") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.AssertEquals(t, "", r.URL.RawQuery) + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusConflict) + fmt.Fprint(w, `{"errors":[{"status":409,"title":"Conflict","detail":"Inventory is in use.","code":"placement.inventory.inuse"}]}`) + }) +} + +func HandleResourceProviderDeleteInventoriesSuccess(t *testing.T, fakeServer th.FakeServer) { + inventoriesDeleteURL := fmt.Sprintf("/resource_providers/%s/inventories", ResourceProviderTestID) + + fakeServer.Mux.HandleFunc(inventoriesDeleteURL, + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "DELETE") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.AssertEquals(t, "", r.URL.RawQuery) + w.WriteHeader(http.StatusNoContent) + }) +} + +func HandleResourceProviderDeleteInventoriesConflict(t *testing.T, fakeServer th.FakeServer) { + inventoriesDeleteURL := fmt.Sprintf("/resource_providers/%s/inventories", ResourceProviderTestID) + + fakeServer.Mux.HandleFunc(inventoriesDeleteURL, + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "DELETE") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.AssertEquals(t, "", r.URL.RawQuery) + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusConflict) + fmt.Fprint(w, `{"errors":[{"status":409,"title":"Conflict","detail":"Inventory is in use.","code":"placement.inventory.inuse"}]}`) + }) +} + func HandleResourceProviderGetAllocations(t *testing.T, fakeServer th.FakeServer) { allocationsTestUrl := fmt.Sprintf("/resource_providers/%s/allocations", ResourceProviderTestID) diff --git a/openstack/placement/v1/resourceproviders/testing/requests_test.go b/openstack/placement/v1/resourceproviders/testing/requests_test.go index 5b12d37c89..693b0d80ff 100644 --- a/openstack/placement/v1/resourceproviders/testing/requests_test.go +++ b/openstack/placement/v1/resourceproviders/testing/requests_test.go @@ -193,6 +193,46 @@ func TestUpdateResourceProviderInventoryNotFound(t *testing.T) { th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } +func TestDeleteResourceProviderInventorySuccess(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleResourceProviderDeleteInventorySuccess(t, fakeServer) + + err := resourceproviders.DeleteInventory(context.TODO(), client.ServiceClient(fakeServer), ResourceProviderTestID, PresentInventoryResourceClass).ExtractErr() + th.AssertNoErr(t, err) +} + +func TestDeleteResourceProviderInventoryInUse(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleResourceProviderDeleteInventoryInUse(t, fakeServer) + + err := resourceproviders.DeleteInventory(context.TODO(), client.ServiceClient(fakeServer), ResourceProviderTestID, PresentInventoryResourceClass).ExtractErr() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusConflict)) +} + +func TestDeleteResourceProviderInventoriesSuccess(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleResourceProviderDeleteInventoriesSuccess(t, fakeServer) + + err := resourceproviders.DeleteInventories(context.TODO(), client.ServiceClient(fakeServer), ResourceProviderTestID).ExtractErr() + th.AssertNoErr(t, err) +} + +func TestDeleteResourceProviderInventoriesConflict(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleResourceProviderDeleteInventoriesConflict(t, fakeServer) + + err := resourceproviders.DeleteInventories(context.TODO(), client.ServiceClient(fakeServer), ResourceProviderTestID).ExtractErr() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusConflict)) +} + func TestGetResourceProvidersAllocations(t *testing.T) { fakeServer := th.SetupHTTP() defer fakeServer.Teardown() diff --git a/openstack/placement/v1/resourceproviders/urls.go b/openstack/placement/v1/resourceproviders/urls.go index 61d6e1e811..fbc0ff2955 100644 --- a/openstack/placement/v1/resourceproviders/urls.go +++ b/openstack/placement/v1/resourceproviders/urls.go @@ -30,6 +30,10 @@ func getResourceProviderInventoriesURL(client *gophercloud.ServiceClient, resour return client.ServiceURL(apiName, resourceProviderID, "inventories") } +func deleteResourceProviderInventoriesURL(client *gophercloud.ServiceClient, resourceProviderID string) string { + return client.ServiceURL(apiName, resourceProviderID, "inventories") +} + func getResourceProviderInventoryURL(client *gophercloud.ServiceClient, resourceProviderID, resourceClass string) string { return client.ServiceURL(apiName, resourceProviderID, "inventories", resourceClass) } @@ -38,6 +42,10 @@ func updateResourceProviderInventoryURL(client *gophercloud.ServiceClient, resou return client.ServiceURL(apiName, resourceProviderID, "inventories", resourceClass) } +func deleteResourceProviderInventoryURL(client *gophercloud.ServiceClient, resourceProviderID, resourceClass string) string { + return client.ServiceURL(apiName, resourceProviderID, "inventories", resourceClass) +} + func getResourceProviderAllocationsURL(client *gophercloud.ServiceClient, resourceProviderID string) string { return client.ServiceURL(apiName, resourceProviderID, "allocations") } From 0345eacab4c45e614edce5f26d35a8144d01e027 Mon Sep 17 00:00:00 2001 From: Dominik Danelski Date: Tue, 31 Mar 2026 22:10:49 +0200 Subject: [PATCH 356/429] Implement resource_classes DELETE operation Related #526 API reference: https://docs.openstack.org/api-ref/placement/#resource-classes Code reference: https://github.com/openstack/placement/blob/stable/2025.1/placement/handlers/resource_class.py#L90-L110 Signed-off-by: Dominik Danelski --- .../placement/v1/resourceclasses_test.go | 62 +++++++++++++++++++ openstack/placement/v1/resourceclasses/doc.go | 9 +++ .../placement/v1/resourceclasses/requests.go | 9 +++ .../placement/v1/resourceclasses/results.go | 6 ++ .../resourceclasses/testing/fixtures_test.go | 30 +++++++++ .../resourceclasses/testing/requests_test.go | 31 ++++++++++ .../placement/v1/resourceclasses/urls.go | 4 ++ 7 files changed, 151 insertions(+) diff --git a/internal/acceptance/openstack/placement/v1/resourceclasses_test.go b/internal/acceptance/openstack/placement/v1/resourceclasses_test.go index d2ea98fb51..13f7663e40 100644 --- a/internal/acceptance/openstack/placement/v1/resourceclasses_test.go +++ b/internal/acceptance/openstack/placement/v1/resourceclasses_test.go @@ -157,3 +157,65 @@ func TestResourceClassCreateByUpdateNonCustomName(t *testing.T) { // Assert: We get 400 th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) } + +func TestResourceClassDeleteSuccess(t *testing.T) { + // Resource classes were introduced in 1.2 + clients.SkipReleasesBelow(t, "stable/ocata") + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + client.Microversion = "1.2" + + name := strings.ToUpper(tools.RandomString("CUSTOM_", 8)) + createOpts := resourceclasses.CreateOpts{ + Name: name, + } + + // Arrange: Create a resource class to delete + err = resourceclasses.Create(context.TODO(), client, createOpts).ExtractErr() + th.AssertNoErr(t, err) + + // Arrange: Sanity check, the newly created resource class exists + rc, err := resourceclasses.Get(context.TODO(), client, name).Extract() + th.AssertNoErr(t, err) + th.AssertEquals(t, name, rc.Name) + + // Act: Delete the resource class + err = resourceclasses.Delete(context.TODO(), client, name).ExtractErr() + th.AssertNoErr(t, err) + + // Assert: The resource class no longer exists + _, err = resourceclasses.Get(context.TODO(), client, name).Extract() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) +} + +func TestResourceClassDeleteNotFound(t *testing.T) { + // Resource classes were introduced in 1.2 + clients.SkipReleasesBelow(t, "stable/ocata") + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + client.Microversion = "1.2" + + // Act: Try to delete a non-existent resource class + err = resourceclasses.Delete(context.TODO(), client, "CUSTOM_NON_EXISTENT_RC").ExtractErr() + // Assert: We get 404 + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) +} + +func TestResourceClassDeleteStandardClass(t *testing.T) { + // Resource classes were introduced in 1.2 + clients.SkipReleasesBelow(t, "stable/ocata") + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + client.Microversion = "1.2" + + // Act: Try to delete a standard resource class + err = resourceclasses.Delete(context.TODO(), client, "VCPU").ExtractErr() + // Assert: We get 400 + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) +} diff --git a/openstack/placement/v1/resourceclasses/doc.go b/openstack/placement/v1/resourceclasses/doc.go index 53eae204c9..b1535af4ae 100644 --- a/openstack/placement/v1/resourceclasses/doc.go +++ b/openstack/placement/v1/resourceclasses/doc.go @@ -54,5 +54,14 @@ Example to ensure the existence of a resource class using PUT (idempotent creati if err != nil { panic(err) } + +Example to delete a resource class + + placementClient.Microversion = "1.2" + + err := resourceclasses.Delete(context.TODO(), placementClient, "CUSTOM_RESOURCE_CLASS").ExtractErr() + if err != nil { + panic(err) + } */ package resourceclasses diff --git a/openstack/placement/v1/resourceclasses/requests.go b/openstack/placement/v1/resourceclasses/requests.go index 4fccd33c9c..8621eddce5 100644 --- a/openstack/placement/v1/resourceclasses/requests.go +++ b/openstack/placement/v1/resourceclasses/requests.go @@ -62,3 +62,12 @@ func Update(ctx context.Context, client *gophercloud.ServiceClient, name string) _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return } + +// Delete deletes the resource class with the provided name. +func Delete(ctx context.Context, client *gophercloud.ServiceClient, name string) (r DeleteResult) { + resp, err := client.Delete(ctx, deleteURL(client, name), &gophercloud.RequestOpts{ + OkCodes: []int{204}, + }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} diff --git a/openstack/placement/v1/resourceclasses/results.go b/openstack/placement/v1/resourceclasses/results.go index cbd5501b9c..61131c372e 100644 --- a/openstack/placement/v1/resourceclasses/results.go +++ b/openstack/placement/v1/resourceclasses/results.go @@ -47,6 +47,12 @@ type UpdateResult struct { gophercloud.ErrResult } +// DeleteResult is the response from a Delete operation. Call its ExtractErr to +// determine if the request succeeded or failed. +type DeleteResult struct { + gophercloud.ErrResult +} + // ResourceClassesPage contains a single page of all resource classes from a List call. type ResourceClassesPage struct { pagination.SinglePageBase diff --git a/openstack/placement/v1/resourceclasses/testing/fixtures_test.go b/openstack/placement/v1/resourceclasses/testing/fixtures_test.go index 7b0819cdef..cfd5de8847 100644 --- a/openstack/placement/v1/resourceclasses/testing/fixtures_test.go +++ b/openstack/placement/v1/resourceclasses/testing/fixtures_test.go @@ -169,3 +169,33 @@ func HandleUpdateResourceClassNonCustom(t *testing.T, fakeServer th.FakeServer) w.WriteHeader(http.StatusBadRequest) }) } + +func HandleDeleteResourceClassSuccess(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/resource_classes/"+PresentResourceClass, + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "DELETE") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.WriteHeader(http.StatusNoContent) + }) +} + +func HandleDeleteResourceClassNotFound(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/resource_classes/"+AbsentResourceClass, + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "DELETE") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.WriteHeader(http.StatusNotFound) + }) +} + +func HandleDeleteResourceClassStandardClass(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/resource_classes/VCPU", + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "DELETE") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.WriteHeader(http.StatusBadRequest) + }) +} diff --git a/openstack/placement/v1/resourceclasses/testing/requests_test.go b/openstack/placement/v1/resourceclasses/testing/requests_test.go index e1a821f0de..9ff18e6a71 100644 --- a/openstack/placement/v1/resourceclasses/testing/requests_test.go +++ b/openstack/placement/v1/resourceclasses/testing/requests_test.go @@ -103,3 +103,34 @@ func TestUpdateResourceClassNonCustom(t *testing.T) { err := resourceclasses.Update(context.TODO(), client.ServiceClient(fakeServer), "VCPU").ExtractErr() th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) } + +func TestDeleteResourceClassSuccess(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleDeleteResourceClassSuccess(t, fakeServer) + + err := resourceclasses.Delete(context.TODO(), client.ServiceClient(fakeServer), PresentResourceClass).ExtractErr() + th.AssertNoErr(t, err) +} + +func TestDeleteResourceClassNotFound(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleDeleteResourceClassNotFound(t, fakeServer) + + err := resourceclasses.Delete(context.TODO(), client.ServiceClient(fakeServer), AbsentResourceClass).ExtractErr() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) +} + +func TestDeleteResourceClassStandardClass(t *testing.T) { + // Removing standard resource classes is not allowed. + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleDeleteResourceClassStandardClass(t, fakeServer) + + err := resourceclasses.Delete(context.TODO(), client.ServiceClient(fakeServer), "VCPU").ExtractErr() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) +} diff --git a/openstack/placement/v1/resourceclasses/urls.go b/openstack/placement/v1/resourceclasses/urls.go index 3dc3f82d19..85d9f77041 100644 --- a/openstack/placement/v1/resourceclasses/urls.go +++ b/openstack/placement/v1/resourceclasses/urls.go @@ -19,3 +19,7 @@ func getURL(client *gophercloud.ServiceClient, name string) string { func updateURL(client *gophercloud.ServiceClient, name string) string { return client.ServiceURL("resource_classes", name) } + +func deleteURL(client *gophercloud.ServiceClient, name string) string { + return client.ServiceURL("resource_classes", name) +} From 2d54a48f4af39860da3b1cec236472d2afb553dd Mon Sep 17 00:00:00 2001 From: Dominik Danelski Date: Thu, 2 Apr 2026 15:11:50 +0200 Subject: [PATCH 357/429] Implement GET operation on Placement resource provider aggregates Related: #526 API reference: https://docs.openstack.org/api-ref/placement/#list-resource-provider-aggregates Code reference: https://opendev.org/openstack/placement/src/branch/stable/2026.1/placement/handlers/aggregate.py#L81-L99 Signed-off-by: Dominik Danelski --- .../placement/v1/resourceproviders_test.go | 69 +++++++++++++++++++ .../placement/v1/resourceproviders/doc.go | 9 +++ .../v1/resourceproviders/requests.go | 6 ++ .../placement/v1/resourceproviders/results.go | 19 +++++ .../testing/fixtures_test.go | 47 +++++++++++++ .../testing/requests_test.go | 23 +++++++ .../placement/v1/resourceproviders/urls.go | 4 ++ 7 files changed, 177 insertions(+) diff --git a/internal/acceptance/openstack/placement/v1/resourceproviders_test.go b/internal/acceptance/openstack/placement/v1/resourceproviders_test.go index bd6c3f1fa4..3514d7f2b3 100644 --- a/internal/acceptance/openstack/placement/v1/resourceproviders_test.go +++ b/internal/acceptance/openstack/placement/v1/resourceproviders_test.go @@ -4,8 +4,10 @@ package v1 import ( "context" + "net/http" "testing" + "github.com/gophercloud/gophercloud/v2" "github.com/gophercloud/gophercloud/v2/internal/acceptance/clients" "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/resourceproviders" @@ -135,3 +137,70 @@ func TestResourceProviderAllocations(t *testing.T) { tools.PrintResource(t, usage) } + +func TestResourceProviderAggregatesGetSuccess(t *testing.T) { + // Resource_provider_generation in the aggregates response was introduced in microversion 1.19. + clients.SkipReleasesBelow(t, "stable/ocata") + clients.RequireAdmin(t) + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + resourceProvider, err := CreateResourceProvider(t, client) + th.AssertNoErr(t, err) + defer DeleteResourceProvider(t, client, resourceProvider.UUID) + + client.Microversion = "1.19" + + aggregates, err := resourceproviders.GetAggregates(context.TODO(), client, resourceProvider.UUID).Extract() + th.AssertNoErr(t, err) + th.AssertEquals(t, true, aggregates.ResourceProviderGeneration != nil) +} + +func TestResourceProviderAggregatesGetPreGenerationSuccess(t *testing.T) { + // Resource provider aggregates operations were introduced in microversion 1.1. + clients.SkipReleasesBelow(t, "stable/ocata") + clients.RequireAdmin(t) + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + resourceProvider, err := CreateResourceProvider(t, client) + th.AssertNoErr(t, err) + defer DeleteResourceProvider(t, client, resourceProvider.UUID) + + client.Microversion = "1.1" + + aggregates, err := resourceproviders.GetAggregates(context.TODO(), client, resourceProvider.UUID).Extract() + th.AssertNoErr(t, err) + th.AssertEquals(t, 0, len(aggregates.Aggregates)) + th.AssertDeepEquals(t, (*int)(nil), aggregates.ResourceProviderGeneration) +} + +func TestResourceProviderAggregatesGetNegative(t *testing.T) { + // Resource_provider_generation in the aggregates response was introduced in microversion 1.19. + clients.SkipReleasesBelow(t, "stable/ocata") + clients.RequireAdmin(t) + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + client.Microversion = "1.19" + + _, err = resourceproviders.GetAggregates(context.TODO(), client, "00000000-0000-0000-0000-000000000000").Extract() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) +} + +func TestResourceProviderAggregatesGetPreGenerationNegative(t *testing.T) { + // Resource provider aggregates operations were introduced in microversion 1.1. + clients.SkipReleasesBelow(t, "stable/ocata") + clients.RequireAdmin(t) + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + client.Microversion = "1.1" + + _, err = resourceproviders.GetAggregates(context.TODO(), client, "00000000-0000-0000-0000-000000000000").Extract() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) +} diff --git a/openstack/placement/v1/resourceproviders/doc.go b/openstack/placement/v1/resourceproviders/doc.go index d659558f15..efd98b775d 100644 --- a/openstack/placement/v1/resourceproviders/doc.go +++ b/openstack/placement/v1/resourceproviders/doc.go @@ -88,5 +88,14 @@ Example to get resource providers allocations if err != nil { panic(err) } + +Example to get resource providers aggregates + + placementClient.Microversion = "1.1" + + rp, err := resourceproviders.GetAggregates(context.TODO(), placementClient, resourceProviderID).Extract() + if err != nil { + panic(err) + } */ package resourceproviders diff --git a/openstack/placement/v1/resourceproviders/requests.go b/openstack/placement/v1/resourceproviders/requests.go index f0dfa9d66f..5a8ece6876 100644 --- a/openstack/placement/v1/resourceproviders/requests.go +++ b/openstack/placement/v1/resourceproviders/requests.go @@ -176,6 +176,12 @@ func GetTraits(ctx context.Context, client *gophercloud.ServiceClient, resourceP return } +func GetAggregates(ctx context.Context, client *gophercloud.ServiceClient, resourceProviderID string) (r GetAggregatesResult) { + resp, err := client.Get(ctx, getResourceProviderAggregatesURL(client, resourceProviderID), &r.Body, nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + // UpdateTraitsOptsBuilder allows extensions to add additional parameters to the // UpdateTraits request. type UpdateTraitsOptsBuilder interface { diff --git a/openstack/placement/v1/resourceproviders/results.go b/openstack/placement/v1/resourceproviders/results.go index 19b71103e1..3f65f97627 100644 --- a/openstack/placement/v1/resourceproviders/results.go +++ b/openstack/placement/v1/resourceproviders/results.go @@ -66,6 +66,12 @@ type ResourceProviderTraits struct { Traits []string `json:"traits"` } +type ResourceProviderAggregates struct { + // ResourceProviderGeneration is available from microversion 1.19 and later. + ResourceProviderGeneration *int `json:"resource_provider_generation"` + Aggregates []string `json:"aggregates"` +} + // resourceProviderResult is the response of a base ResourceProvider result. type resourceProviderResult struct { gophercloud.Result @@ -178,3 +184,16 @@ func (r GetTraitsResult) Extract() (*ResourceProviderTraits, error) { err := r.ExtractInto(&s) return &s, err } + +// GetAggregatesResult is the response of a Get aggregates operations. Call its Extract method +// to interpret it as a ResourceProviderAggregates. +type GetAggregatesResult struct { + gophercloud.Result +} + +// Extract interprets a GetAggregatesResult as a ResourceProviderAggregates. +func (r GetAggregatesResult) Extract() (*ResourceProviderAggregates, error) { + var s ResourceProviderAggregates + err := r.ExtractInto(&s) + return &s, err +} diff --git a/openstack/placement/v1/resourceproviders/testing/fixtures_test.go b/openstack/placement/v1/resourceproviders/testing/fixtures_test.go index 6ac4b8ca73..d3682a7177 100644 --- a/openstack/placement/v1/resourceproviders/testing/fixtures_test.go +++ b/openstack/placement/v1/resourceproviders/testing/fixtures_test.go @@ -164,6 +164,18 @@ const TraitsBody = ` } ` +const AggregatesBody = ` +{ + "resource_provider_generation": 1, + "aggregates": [ + "6d84f6f6-7736-40ff-84d2-7db47f18ea25", + "f11f14bc-6f17-4f0a-b7c2-44b3e685ccf4" + ] +} +` + +const AbsentResourceProviderID = "non-existent-rp" + var ExpectedResourceProvider1 = resourceproviders.ResourceProvider{ Generation: 1, UUID: "99c09379-6e52-4ef8-9a95-b9ce6f68452e", @@ -268,6 +280,14 @@ var ExpectedTraits = resourceproviders.ResourceProviderTraits{ }, } +var ExpectedAggregates = resourceproviders.ResourceProviderAggregates{ + ResourceProviderGeneration: 1, + Aggregates: []string{ + "6d84f6f6-7736-40ff-84d2-7db47f18ea25", + "f11f14bc-6f17-4f0a-b7c2-44b3e685ccf4", + }, +} + func HandleResourceProviderList(t *testing.T, fakeServer th.FakeServer) { fakeServer.Mux.HandleFunc("/resource_providers", func(w http.ResponseWriter, r *http.Request) { @@ -413,3 +433,30 @@ func HandleResourceProviderDeleteTraits(t *testing.T, fakeServer th.FakeServer) w.WriteHeader(http.StatusNoContent) }) } + +func HandleResourceProviderGetAggregatesSuccess(t *testing.T, fakeServer th.FakeServer) { + aggregatesTestURL := fmt.Sprintf("/resource_providers/%s/aggregates", ResourceProviderTestID) + + fakeServer.Mux.HandleFunc(aggregatesTestURL, + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, AggregatesBody) + }) +} + +func HandleResourceProviderGetAggregatesNotFound(t *testing.T, fakeServer th.FakeServer) { + aggregatesTestURL := fmt.Sprintf("/resource_providers/%s/aggregates", AbsentResourceProviderID) + + fakeServer.Mux.HandleFunc(aggregatesTestURL, + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.WriteHeader(http.StatusNotFound) + }) +} diff --git a/openstack/placement/v1/resourceproviders/testing/requests_test.go b/openstack/placement/v1/resourceproviders/testing/requests_test.go index 4633c81136..4a97672c25 100644 --- a/openstack/placement/v1/resourceproviders/testing/requests_test.go +++ b/openstack/placement/v1/resourceproviders/testing/requests_test.go @@ -2,8 +2,10 @@ package testing import ( "context" + "net/http" "testing" + "github.com/gophercloud/gophercloud/v2" "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/resourceproviders" "github.com/gophercloud/gophercloud/v2/pagination" @@ -167,3 +169,24 @@ func TestDeleteResourceProvidersTraits(t *testing.T) { err := resourceproviders.DeleteTraits(context.TODO(), client.ServiceClient(fakeServer), ResourceProviderTestID).ExtractErr() th.AssertNoErr(t, err) } + +func TestGetResourceProviderAggregatesSuccess(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleResourceProviderGetAggregatesSuccess(t, fakeServer) + + actual, err := resourceproviders.GetAggregates(context.TODO(), client.ServiceClient(fakeServer), ResourceProviderTestID).Extract() + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedAggregates, *actual) +} + +func TestGetResourceProviderAggregatesNotFound(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleResourceProviderGetAggregatesNotFound(t, fakeServer) + + _, err := resourceproviders.GetAggregates(context.TODO(), client.ServiceClient(fakeServer), AbsentResourceProviderID).Extract() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) +} diff --git a/openstack/placement/v1/resourceproviders/urls.go b/openstack/placement/v1/resourceproviders/urls.go index 037149b684..821fdcf57a 100644 --- a/openstack/placement/v1/resourceproviders/urls.go +++ b/openstack/placement/v1/resourceproviders/urls.go @@ -37,3 +37,7 @@ func getResourceProviderAllocationsURL(client *gophercloud.ServiceClient, resour func getResourceProviderTraitsURL(client *gophercloud.ServiceClient, resourceProviderID string) string { return client.ServiceURL(apiName, resourceProviderID, "traits") } + +func getResourceProviderAggregatesURL(client *gophercloud.ServiceClient, resourceProviderID string) string { + return client.ServiceURL(apiName, resourceProviderID, "aggregates") +} From 20b5ab81576899b261dd79c3a0de5e086f67ca83 Mon Sep 17 00:00:00 2001 From: Dominik Danelski Date: Thu, 2 Apr 2026 15:16:25 +0200 Subject: [PATCH 358/429] Implement PUT operation on Placement resource provider aggregates Related: #526 API reference: https://docs.openstack.org/api-ref/placement/#update-resource-provider-aggregates Code reference: https://opendev.org/openstack/placement/src/branch/stable/2026.1/placement/handlers/aggregate.py#L102-L132 Signed-off-by: Dominik Danelski --- .../placement/v1/resourceproviders_test.go | 69 ++++++++ .../placement/v1/resourceproviders/doc.go | 17 ++ .../v1/resourceproviders/requests.go | 32 ++++ .../testing/fixtures_test.go | 150 +++++++++++++++++- .../testing/requests_test.go | 54 +++++++ .../placement/v1/resourceproviders/urls.go | 4 + 6 files changed, 324 insertions(+), 2 deletions(-) diff --git a/internal/acceptance/openstack/placement/v1/resourceproviders_test.go b/internal/acceptance/openstack/placement/v1/resourceproviders_test.go index 3514d7f2b3..1a519c9202 100644 --- a/internal/acceptance/openstack/placement/v1/resourceproviders_test.go +++ b/internal/acceptance/openstack/placement/v1/resourceproviders_test.go @@ -5,6 +5,7 @@ package v1 import ( "context" "net/http" + "slices" "testing" "github.com/gophercloud/gophercloud/v2" @@ -204,3 +205,71 @@ func TestResourceProviderAggregatesGetPreGenerationNegative(t *testing.T) { _, err = resourceproviders.GetAggregates(context.TODO(), client, "00000000-0000-0000-0000-000000000000").Extract() th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } + +func TestResourceProviderAggregatesUpdateSuccess(t *testing.T) { + // resource_provider_generation is required in the PUT request body from microversion 1.19. + clients.SkipReleasesBelow(t, "stable/ocata") + clients.RequireAdmin(t) + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + resourceProvider, err := CreateResourceProvider(t, client) + th.AssertNoErr(t, err) + defer DeleteResourceProvider(t, client, resourceProvider.UUID) + + client.Microversion = "1.19" + + before, err := resourceproviders.GetAggregates(context.TODO(), client, resourceProvider.UUID).Extract() + th.AssertNoErr(t, err) + th.AssertEquals(t, true, before.ResourceProviderGeneration != nil) + + updateOpts := resourceproviders.UpdateAggregatesOpts{ + ResourceProviderGeneration: before.ResourceProviderGeneration, + Aggregates: []string{ + "6d84f6f6-7736-40ff-84d2-7db47f18ea25", + "f11f14bc-6f17-4f0a-b7c2-44b3e685ccf4", + }, + } + + _, err = resourceproviders.UpdateAggregates(context.TODO(), client, resourceProvider.UUID, updateOpts).Extract() + th.AssertNoErr(t, err) + + after, err := resourceproviders.GetAggregates(context.TODO(), client, resourceProvider.UUID).Extract() + th.AssertNoErr(t, err) + th.AssertEquals(t, len(updateOpts.Aggregates), len(after.Aggregates)) + + for _, aggregate := range updateOpts.Aggregates { + th.AssertEquals(t, true, slices.Contains(after.Aggregates, aggregate)) + } +} + +func TestResourceProviderAggregatesUpdateNegative(t *testing.T) { + // resource_provider_generation is required in the PUT request body from microversion 1.19. + clients.SkipReleasesBelow(t, "stable/ocata") + clients.RequireAdmin(t) + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + resourceProvider, err := CreateResourceProvider(t, client) + th.AssertNoErr(t, err) + defer DeleteResourceProvider(t, client, resourceProvider.UUID) + + client.Microversion = "1.19" + + current, err := resourceproviders.GetAggregates(context.TODO(), client, resourceProvider.UUID).Extract() + th.AssertNoErr(t, err) + th.AssertEquals(t, true, current.ResourceProviderGeneration != nil) + wrongGeneration := *current.ResourceProviderGeneration + 100 + + updateOpts := resourceproviders.UpdateAggregatesOpts{ + ResourceProviderGeneration: &wrongGeneration, + Aggregates: []string{ + "6d84f6f6-7736-40ff-84d2-7db47f18ea25", + }, + } + + _, err = resourceproviders.UpdateAggregates(context.TODO(), client, resourceProvider.UUID, updateOpts).Extract() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusConflict)) +} diff --git a/openstack/placement/v1/resourceproviders/doc.go b/openstack/placement/v1/resourceproviders/doc.go index efd98b775d..7164e6cfb7 100644 --- a/openstack/placement/v1/resourceproviders/doc.go +++ b/openstack/placement/v1/resourceproviders/doc.go @@ -97,5 +97,22 @@ Example to get resource providers aggregates if err != nil { panic(err) } + +Example to update resource providers aggregates + + placementClient.Microversion = "1.1" + + updateOpts := resourceproviders.UpdateAggregatesOpts{ + ResourceProviderGeneration: rp.ResourceProviderGeneration, + Aggregates: []string{ + "6d84f6f6-7736-40ff-84d2-7db47f18ea25", + "f11f14bc-6f17-4f0a-b7c2-44b3e685ccf4", + }, + } + + rp, err = resourceproviders.UpdateAggregates(context.TODO(), placementClient, resourceProviderID, updateOpts).Extract() + if err != nil { + panic(err) + } */ package resourceproviders diff --git a/openstack/placement/v1/resourceproviders/requests.go b/openstack/placement/v1/resourceproviders/requests.go index 5a8ece6876..fef0fe1a9b 100644 --- a/openstack/placement/v1/resourceproviders/requests.go +++ b/openstack/placement/v1/resourceproviders/requests.go @@ -182,6 +182,38 @@ func GetAggregates(ctx context.Context, client *gophercloud.ServiceClient, resou return } +// UpdateAggregatesOptsBuilder allows extensions to add additional parameters to the +// UpdateAggregates request. +type UpdateAggregatesOptsBuilder interface { + ToResourceProviderUpdateAggregatesMap() (map[string]any, error) +} + +// UpdateAggregatesOpts represents options used to update aggregates of a resource provider. +type UpdateAggregatesOpts struct { + // ResourceProviderGeneration is required from microversion 1.19 and later. + ResourceProviderGeneration *int `json:"resource_provider_generation,omitempty"` + Aggregates []string `json:"aggregates"` +} + +// ToResourceProviderUpdateAggregatesMap constructs a request body from UpdateAggregatesOpts. +func (opts UpdateAggregatesOpts) ToResourceProviderUpdateAggregatesMap() (map[string]any, error) { + return gophercloud.BuildRequestBody(opts, "") +} + +func UpdateAggregates(ctx context.Context, client *gophercloud.ServiceClient, resourceProviderID string, opts UpdateAggregatesOptsBuilder) (r GetAggregatesResult) { + b, err := opts.ToResourceProviderUpdateAggregatesMap() + if err != nil { + r.Err = err + return + } + + resp, err := client.Put(ctx, updateResourceProviderAggregatesURL(client, resourceProviderID), b, &r.Body, &gophercloud.RequestOpts{ + OkCodes: []int{200}, + }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + // UpdateTraitsOptsBuilder allows extensions to add additional parameters to the // UpdateTraits request. type UpdateTraitsOptsBuilder interface { diff --git a/openstack/placement/v1/resourceproviders/testing/fixtures_test.go b/openstack/placement/v1/resourceproviders/testing/fixtures_test.go index d3682a7177..78132e7048 100644 --- a/openstack/placement/v1/resourceproviders/testing/fixtures_test.go +++ b/openstack/placement/v1/resourceproviders/testing/fixtures_test.go @@ -174,7 +174,35 @@ const AggregatesBody = ` } ` -const AbsentResourceProviderID = "non-existent-rp" +const AggregatesBodyPreGeneration = ` +{ + "aggregates": [ + "6d84f6f6-7736-40ff-84d2-7db47f18ea25", + "f11f14bc-6f17-4f0a-b7c2-44b3e685ccf4" + ] +} +` + +const AggregatesUpdateBody = ` +{ + "resource_provider_generation": 1, + "aggregates": [ + "89f68995-4fd8-4f8b-a03e-7d5980762ff2", + "16d0e5f2-7f66-4f32-9040-b09de2f40afd" + ] +} +` + +const AggregatesUpdateBodyPreGeneration = ` +{ + "aggregates": [ + "89f68995-4fd8-4f8b-a03e-7d5980762ff2", + "16d0e5f2-7f66-4f32-9040-b09de2f40afd" + ] +} +` + +const AbsentResourceProviderID = "00000000-0000-0000-0000-000000000000" var ExpectedResourceProvider1 = resourceproviders.ResourceProvider{ Generation: 1, @@ -280,14 +308,41 @@ var ExpectedTraits = resourceproviders.ResourceProviderTraits{ }, } +var expectedAggregatesGeneration = 1 + var ExpectedAggregates = resourceproviders.ResourceProviderAggregates{ - ResourceProviderGeneration: 1, + ResourceProviderGeneration: &expectedAggregatesGeneration, + Aggregates: []string{ + "6d84f6f6-7736-40ff-84d2-7db47f18ea25", + "f11f14bc-6f17-4f0a-b7c2-44b3e685ccf4", + }, +} + +var ExpectedAggregatesPreGeneration = resourceproviders.ResourceProviderAggregates{ + ResourceProviderGeneration: nil, Aggregates: []string{ "6d84f6f6-7736-40ff-84d2-7db47f18ea25", "f11f14bc-6f17-4f0a-b7c2-44b3e685ccf4", }, } +var expectedUpdatedAggregatesGeneration = 1 + +var ExpectedUpdatedAggregates = resourceproviders.ResourceProviderAggregates{ + ResourceProviderGeneration: &expectedUpdatedAggregatesGeneration, + Aggregates: []string{ + "89f68995-4fd8-4f8b-a03e-7d5980762ff2", + "16d0e5f2-7f66-4f32-9040-b09de2f40afd", + }, +} + +var ExpectedUpdatedAggregatesPreGeneration = resourceproviders.ResourceProviderAggregates{ + Aggregates: []string{ + "89f68995-4fd8-4f8b-a03e-7d5980762ff2", + "16d0e5f2-7f66-4f32-9040-b09de2f40afd", + }, +} + func HandleResourceProviderList(t *testing.T, fakeServer th.FakeServer) { fakeServer.Mux.HandleFunc("/resource_providers", func(w http.ResponseWriter, r *http.Request) { @@ -449,6 +504,21 @@ func HandleResourceProviderGetAggregatesSuccess(t *testing.T, fakeServer th.Fake }) } +func HandleResourceProviderGetAggregatesPreGenerationSuccess(t *testing.T, fakeServer th.FakeServer) { + aggregatesTestURL := fmt.Sprintf("/resource_providers/%s/aggregates", ResourceProviderTestID) + + fakeServer.Mux.HandleFunc(aggregatesTestURL, + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, AggregatesBodyPreGeneration) + }) +} + func HandleResourceProviderGetAggregatesNotFound(t *testing.T, fakeServer th.FakeServer) { aggregatesTestURL := fmt.Sprintf("/resource_providers/%s/aggregates", AbsentResourceProviderID) @@ -460,3 +530,79 @@ func HandleResourceProviderGetAggregatesNotFound(t *testing.T, fakeServer th.Fak w.WriteHeader(http.StatusNotFound) }) } + +func HandleResourceProviderUpdateAndGetAggregatesSuccess(t *testing.T, fakeServer th.FakeServer) { + aggregatesTestURL := fmt.Sprintf("/resource_providers/%s/aggregates", ResourceProviderTestID) + + // This handler must cover PUT and GET because the test updates and then fetches on the same path. + body := AggregatesBody + + fakeServer.Mux.HandleFunc(aggregatesTestURL, + func(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case http.MethodGet: + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + fmt.Fprint(w, body) + case http.MethodPut: + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestJSONRequest(t, r, AggregatesUpdateBody) + + body = AggregatesUpdateBody + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + fmt.Fprint(w, body) + default: + w.WriteHeader(http.StatusMethodNotAllowed) + } + }) +} + +func HandleResourceProviderUpdateAndGetAggregatesPreGenerationSuccess(t *testing.T, fakeServer th.FakeServer) { + aggregatesTestURL := fmt.Sprintf("/resource_providers/%s/aggregates", ResourceProviderTestID) + + // Pre-generation variant of the same update-then-fetch flow on a shared endpoint. + body := AggregatesBodyPreGeneration + + fakeServer.Mux.HandleFunc(aggregatesTestURL, + func(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case http.MethodGet: + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + fmt.Fprint(w, body) + case http.MethodPut: + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestJSONRequest(t, r, AggregatesUpdateBodyPreGeneration) + + body = AggregatesUpdateBodyPreGeneration + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + fmt.Fprint(w, body) + default: + w.WriteHeader(http.StatusMethodNotAllowed) + } + }) +} + +func HandleResourceProviderUpdateAggregatesConflict(t *testing.T, fakeServer th.FakeServer) { + aggregatesTestURL := fmt.Sprintf("/resource_providers/%s/aggregates", ResourceProviderTestID) + + fakeServer.Mux.HandleFunc(aggregatesTestURL, + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "PUT") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.WriteHeader(http.StatusConflict) + }) +} diff --git a/openstack/placement/v1/resourceproviders/testing/requests_test.go b/openstack/placement/v1/resourceproviders/testing/requests_test.go index 4a97672c25..5cb6101ddb 100644 --- a/openstack/placement/v1/resourceproviders/testing/requests_test.go +++ b/openstack/placement/v1/resourceproviders/testing/requests_test.go @@ -181,6 +181,17 @@ func TestGetResourceProviderAggregatesSuccess(t *testing.T) { th.AssertDeepEquals(t, ExpectedAggregates, *actual) } +func TestGetResourceProviderAggregatesPreGenerationSuccess(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleResourceProviderGetAggregatesPreGenerationSuccess(t, fakeServer) + + actual, err := resourceproviders.GetAggregates(context.TODO(), client.ServiceClient(fakeServer), ResourceProviderTestID).Extract() + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedAggregatesPreGeneration, *actual) +} + func TestGetResourceProviderAggregatesNotFound(t *testing.T) { fakeServer := th.SetupHTTP() defer fakeServer.Teardown() @@ -190,3 +201,46 @@ func TestGetResourceProviderAggregatesNotFound(t *testing.T) { _, err := resourceproviders.GetAggregates(context.TODO(), client.ServiceClient(fakeServer), AbsentResourceProviderID).Extract() th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } + +func TestUpdateResourceProviderAggregatesSuccess(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleResourceProviderUpdateAndGetAggregatesSuccess(t, fakeServer) + + updateOpts := resourceproviders.UpdateAggregatesOpts(ExpectedUpdatedAggregates) + _, err := resourceproviders.UpdateAggregates(context.TODO(), client.ServiceClient(fakeServer), ResourceProviderTestID, updateOpts).Extract() + th.AssertNoErr(t, err) + + actual, err := resourceproviders.GetAggregates(context.TODO(), client.ServiceClient(fakeServer), ResourceProviderTestID).Extract() + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedUpdatedAggregates, *actual) +} + +func TestUpdateResourceProviderAggregatesPreGenerationSuccess(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleResourceProviderUpdateAndGetAggregatesPreGenerationSuccess(t, fakeServer) + + updateOpts := resourceproviders.UpdateAggregatesOpts{ + Aggregates: ExpectedUpdatedAggregatesPreGeneration.Aggregates, + } + _, err := resourceproviders.UpdateAggregates(context.TODO(), client.ServiceClient(fakeServer), ResourceProviderTestID, updateOpts).Extract() + th.AssertNoErr(t, err) + + actual, err := resourceproviders.GetAggregates(context.TODO(), client.ServiceClient(fakeServer), ResourceProviderTestID).Extract() + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedUpdatedAggregatesPreGeneration, *actual) +} + +func TestUpdateResourceProviderAggregatesConflict(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleResourceProviderUpdateAggregatesConflict(t, fakeServer) + + updateOpts := resourceproviders.UpdateAggregatesOpts(ExpectedUpdatedAggregates) + _, err := resourceproviders.UpdateAggregates(context.TODO(), client.ServiceClient(fakeServer), ResourceProviderTestID, updateOpts).Extract() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusConflict)) +} diff --git a/openstack/placement/v1/resourceproviders/urls.go b/openstack/placement/v1/resourceproviders/urls.go index 821fdcf57a..f661b362cf 100644 --- a/openstack/placement/v1/resourceproviders/urls.go +++ b/openstack/placement/v1/resourceproviders/urls.go @@ -41,3 +41,7 @@ func getResourceProviderTraitsURL(client *gophercloud.ServiceClient, resourcePro func getResourceProviderAggregatesURL(client *gophercloud.ServiceClient, resourceProviderID string) string { return client.ServiceURL(apiName, resourceProviderID, "aggregates") } + +func updateResourceProviderAggregatesURL(client *gophercloud.ServiceClient, resourceProviderID string) string { + return client.ServiceURL(apiName, resourceProviderID, "aggregates") +} From ef5741426842072b762dbd731371dd4e3ae89d32 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Apr 2026 09:05:11 +0000 Subject: [PATCH 359/429] build(deps): bump github/codeql-action from 4.34.1 to 4.35.1 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.34.1 to 4.35.1. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/38697555549f1db7851b81482ff19f1fa5c4fedc...c10b8064de6f491fea524254123dbe5e09572f13) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 4.35.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql-analysis.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yaml b/.github/workflows/codeql-analysis.yaml index 12d4008b74..3d11b8f50a 100644 --- a/.github/workflows/codeql-analysis.yaml +++ b/.github/workflows/codeql-analysis.yaml @@ -29,12 +29,12 @@ jobs: cache: true - name: Initialize CodeQL - uses: github/codeql-action/init@38697555549f1db7851b81482ff19f1fa5c4fedc # v4 + uses: github/codeql-action/init@c10b8064de6f491fea524254123dbe5e09572f13 # v4 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@38697555549f1db7851b81482ff19f1fa5c4fedc # v4 + uses: github/codeql-action/autobuild@c10b8064de6f491fea524254123dbe5e09572f13 # v4 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@38697555549f1db7851b81482ff19f1fa5c4fedc # v4 + uses: github/codeql-action/analyze@c10b8064de6f491fea524254123dbe5e09572f13 # v4 From 5894e298ab2419b24693b36140f3b315faf1d20e Mon Sep 17 00:00:00 2001 From: jlarriba Date: Mon, 23 Feb 2026 15:30:41 +0100 Subject: [PATCH 360/429] Add metric-storage (Aetos) v1 service support Aetos is a Keystone-authenticated reverse proxy for Prometheus that enforces multi-tenant RBAC on all Prometheus queries. This adds Go bindings for the Prometheus HTTP API exposed under /api/v1/ with OpenStack authentication. Supported operations: Query, Labels, LabelValues, Series, Targets, RuntimeInfo, CleanTombstones, DeleteSeries, Snapshot. --- .github/workflows/functional-metric.yaml | 105 ++++++ Makefile | 6 +- internal/acceptance/clients/clients.go | 21 ++ .../openstack/metric/v1/metrics_test.go | 80 +++++ .../acceptance/openstack/metric/v1/pkg.go | 4 + openstack/client.go | 8 + openstack/metric/v1/metrics/doc.go | 59 ++++ openstack/metric/v1/metrics/requests.go | 263 ++++++++++++++ openstack/metric/v1/metrics/results.go | 298 ++++++++++++++++ openstack/metric/v1/metrics/testing/doc.go | 2 + .../v1/metrics/testing/fixtures_test.go | 327 ++++++++++++++++++ .../v1/metrics/testing/requests_test.go | 109 ++++++ openstack/metric/v1/metrics/urls.go | 39 +++ 13 files changed, 1320 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/functional-metric.yaml create mode 100644 internal/acceptance/openstack/metric/v1/metrics_test.go create mode 100644 internal/acceptance/openstack/metric/v1/pkg.go create mode 100644 openstack/metric/v1/metrics/doc.go create mode 100644 openstack/metric/v1/metrics/requests.go create mode 100644 openstack/metric/v1/metrics/results.go create mode 100644 openstack/metric/v1/metrics/testing/doc.go create mode 100644 openstack/metric/v1/metrics/testing/fixtures_test.go create mode 100644 openstack/metric/v1/metrics/testing/requests_test.go create mode 100644 openstack/metric/v1/metrics/urls.go diff --git a/.github/workflows/functional-metric.yaml b/.github/workflows/functional-metric.yaml new file mode 100644 index 0000000000..8f60039792 --- /dev/null +++ b/.github/workflows/functional-metric.yaml @@ -0,0 +1,105 @@ +name: functional-metric +on: + merge_group: + pull_request: + schedule: + - cron: '0 0 */3 * *' +jobs: + functional-metric: + permissions: + contents: read + strategy: + fail-fast: false + matrix: + include: + - name: "master" + openstack_version: "master" + ubuntu_version: "24.04" + devstack_conf_overrides: | + # ensure we're using a working version of setuptools + if [ -n "\$TOP_DIR" ]; then + sed -i 's/setuptools\[core\]$/setuptools[core]==79.0.1/g' \$TOP_DIR/lib/infra \$TOP_DIR/inc/python + sed -i 's/pip_install "-U" "pbr"/pip_install "-U" "pbr" "setuptools[core]==79.0.1"/g' \$TOP_DIR/lib/infra + fi + runs-on: ubuntu-${{ matrix.ubuntu_version }} + name: Aetos on OpenStack ${{ matrix.name }} + steps: + - name: Checkout Gophercloud + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Check changed files + uses: ./.github/actions/file-filter + id: changed-files + with: + patterns: | + openstack/auth_env.go + openstack/client.go + openstack/endpoint.go + openstack/endpoint_location.go + openstack/config/provider_client.go + openstack/utils/choose_version.go + openstack/utils/discovery.go + **metric** + .github/workflows/functional-metric.yaml + + - name: Skip tests for unrelated changed-files + if: ${{ ! fromJSON(steps.changed-files.outputs.matches) }} + run: | + echo "No relevant files changed - skipping tests for ${{ matrix.name }}" + echo "TESTS_SKIPPED=true" >> $GITHUB_ENV + + - name: Deploy devstack + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} + uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 # v0.19 + with: + branch: ${{ matrix.openstack_version }} + conf_overrides: | + enable_plugin devstack-plugin-prometheus https://opendev.org/openstack/devstack-plugin-prometheus ${{ matrix.openstack_version }} + enable_plugin ceilometer https://opendev.org/openstack/ceilometer ${{ matrix.openstack_version }} + CEILOMETER_BACKEND=sg-core + PROMETHEUS_CUSTOM_SCRAPE_TARGETS="localhost:3000" + enable_plugin sg-core https://github.com/openstack-k8s-operators/sg-core main + enable_plugin aetos https://opendev.org/openstack/aetos ${{ matrix.openstack_version }} + + ${{ matrix.devstack_conf_overrides }} + enabled_services: "prometheus,node_exporter,openstack_exporter,ceilometer-acompute,ceilometer-acentral,ceilometer-anotification,sg-core,aetos,openstack-cli-server" + + - name: Checkout go + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} + uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 + with: + go-version-file: 'go.mod' + cache: true + + - name: Run Gophercloud acceptance tests + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} + run: | + source ${{ github.workspace }}/script/stackenv + make acceptance-metric + echo "TESTS_RUN=true" >> $GITHUB_ENV + env: + DEVSTACK_PATH: ${{ github.workspace }}/devstack + OS_BRANCH: ${{ matrix.openstack_version }} + + - name: Generate logs on failure + run: ./script/collectlogs + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} + + - name: Upload logs artifacts on failure + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: functional-metric-${{ matrix.name }}-${{ github.run_id }} + path: /tmp/devstack-logs/* + + - name: Set job status + run: | + if [[ "$TESTS_SKIPPED" == "true" || "$TESTS_RUN" == "true" ]]; then + echo "Job completed successfully (either ran tests or skipped appropriately)" + exit 0 + else + echo "Job failed - neither tests ran nor were properly skipped" + exit 1 + fi diff --git a/Makefile b/Makefile index 79411c0026..6b9d043cf2 100644 --- a/Makefile +++ b/Makefile @@ -43,7 +43,7 @@ coverage: $(GO_TEST) -shuffle on -covermode count -coverprofile cover.out -coverpkg=./... ./... .PHONY: coverage -acceptance: acceptance-basic acceptance-baremetal acceptance-blockstorage acceptance-compute acceptance-container acceptance-containerinfra acceptance-db acceptance-dns acceptance-identity acceptance-image acceptance-keymanager acceptance-loadbalancer acceptance-messaging acceptance-networking acceptance-objectstorage acceptance-orchestration acceptance-placement acceptance-sharedfilesystems acceptance-workflow +acceptance: acceptance-basic acceptance-baremetal acceptance-blockstorage acceptance-compute acceptance-container acceptance-containerinfra acceptance-db acceptance-dns acceptance-identity acceptance-image acceptance-keymanager acceptance-loadbalancer acceptance-messaging acceptance-metric acceptance-networking acceptance-objectstorage acceptance-orchestration acceptance-placement acceptance-sharedfilesystems acceptance-workflow .PHONY: acceptance acceptance-basic: @@ -102,6 +102,10 @@ acceptance-messaging: $(GO_TEST) -timeout $(TIMEOUT) -tags "fixtures acceptance" ./internal/acceptance/openstack/messaging/... .PHONY: acceptance-messaging +acceptance-metric: + $(GO_TEST) -timeout $(TIMEOUT) -tags "fixtures acceptance" ./internal/acceptance/openstack/metric/... +.PHONY: acceptance-metric + acceptance-networking: $(GO_TEST) -timeout $(TIMEOUT) -tags "fixtures acceptance" ./internal/acceptance/openstack/networking/... .PHONY: acceptance-networking diff --git a/internal/acceptance/clients/clients.go b/internal/acceptance/clients/clients.go index 8f9b8de35f..a2d0b0a69b 100644 --- a/internal/acceptance/clients/clients.go +++ b/internal/acceptance/clients/clients.go @@ -585,6 +585,27 @@ func NewMessagingV2Client(clientID string) (*gophercloud.ServiceClient, error) { }) } +// NewMetricV1Client returns a *ServiceClient for making calls +// to the OpenStack Metric v1 API. An error will be returned +// if authentication or client creation was not possible. +func NewMetricV1Client() (*gophercloud.ServiceClient, error) { + ao, err := openstack.AuthOptionsFromEnv() + if err != nil { + return nil, err + } + + client, err := openstack.AuthenticatedClient(context.TODO(), ao) + if err != nil { + return nil, err + } + + client = configureDebug(client) + + return openstack.NewMetricV1(context.TODO(), client, gophercloud.EndpointOpts{ + Region: os.Getenv("OS_REGION_NAME"), + }) +} + // NewContainerV1Client returns a *ServiceClient for making calls // to the OpenStack Container V1 API. An error will be returned // if authentication or client creation was not possible. diff --git a/internal/acceptance/openstack/metric/v1/metrics_test.go b/internal/acceptance/openstack/metric/v1/metrics_test.go new file mode 100644 index 0000000000..6fee465d62 --- /dev/null +++ b/internal/acceptance/openstack/metric/v1/metrics_test.go @@ -0,0 +1,80 @@ +//go:build acceptance || metric || metrics + +package v1 + +import ( + "context" + "testing" + + "github.com/gophercloud/gophercloud/v2/internal/acceptance/clients" + "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" + "github.com/gophercloud/gophercloud/v2/openstack/metric/v1/metrics" + th "github.com/gophercloud/gophercloud/v2/testhelper" +) + +func TestMetricQuery(t *testing.T) { + client, err := clients.NewMetricV1Client() + th.AssertNoErr(t, err) + + result, err := metrics.Query(context.TODO(), client, metrics.QueryOpts{ + Query: "up", + }).Extract() + th.AssertNoErr(t, err) + + tools.PrintResource(t, result) + th.AssertEquals(t, result.ResultType, "vector") +} + +func TestMetricLabels(t *testing.T) { + client, err := clients.NewMetricV1Client() + th.AssertNoErr(t, err) + + result, err := metrics.Labels(context.TODO(), client, nil).Extract() + th.AssertNoErr(t, err) + + tools.PrintResource(t, result) + if len(result) == 0 { + t.Fatal("expected at least one label") + } +} + +func TestMetricLabelValues(t *testing.T) { + client, err := clients.NewMetricV1Client() + th.AssertNoErr(t, err) + + result, err := metrics.LabelValues(context.TODO(), client, "__name__", nil).Extract() + th.AssertNoErr(t, err) + + tools.PrintResource(t, result) + if len(result) == 0 { + t.Fatal("expected at least one label value") + } +} + +func TestMetricSeries(t *testing.T) { + client, err := clients.NewMetricV1Client() + th.AssertNoErr(t, err) + + result, err := metrics.Series(context.TODO(), client, metrics.SeriesOpts{ + Match: []string{`{__name__="up"}`}, + }).Extract() + th.AssertNoErr(t, err) + + tools.PrintResource(t, result) + if len(result) == 0 { + t.Fatal("expected at least one series") + } +} + +func TestMetricRuntimeInfo(t *testing.T) { + client, err := clients.NewMetricV1Client() + th.AssertNoErr(t, err) + + result, err := metrics.RuntimeInfo(context.TODO(), client).Extract() + th.AssertNoErr(t, err) + + tools.PrintResource(t, result) + if result.StorageRetention == "" { + t.Fatal("expected non-empty StorageRetention") + } +} diff --git a/internal/acceptance/openstack/metric/v1/pkg.go b/internal/acceptance/openstack/metric/v1/pkg.go new file mode 100644 index 0000000000..05e9b4a1ab --- /dev/null +++ b/internal/acceptance/openstack/metric/v1/pkg.go @@ -0,0 +1,4 @@ +//go:build acceptance || metric + +// Package v1 contains acceptance tests for the OpenStack metric-storage v1 service. +package v1 diff --git a/openstack/client.go b/openstack/client.go index 234f23eba2..4de89ab4ea 100644 --- a/openstack/client.go +++ b/openstack/client.go @@ -464,6 +464,14 @@ func NewLoadBalancerV2(ctx context.Context, client *gophercloud.ProviderClient, return sc, err } +// NewMetricV1 creates a ServiceClient that may be used with the v1 metric-storage +// service (Aetos). +func NewMetricV1(ctx context.Context, client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { + sc, err := initClientOpts(ctx, client, eo, "metric-storage", 1) + sc.ResourceBase = sc.Endpoint + "api/v1/" + return sc, err +} + // NewMessagingV2 creates a ServiceClient that may be used with the v2 messaging // service. func NewMessagingV2(ctx context.Context, client *gophercloud.ProviderClient, clientID string, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { diff --git a/openstack/metric/v1/metrics/doc.go b/openstack/metric/v1/metrics/doc.go new file mode 100644 index 0000000000..410dc07735 --- /dev/null +++ b/openstack/metric/v1/metrics/doc.go @@ -0,0 +1,59 @@ +/* +Package metrics provides interaction with the Prometheus HTTP API through the +OpenStack Aetos service (metric-storage). + +Aetos acts as a Keystone-authenticated reverse proxy for Prometheus, enforcing +multi-tenant RBAC on all Prometheus queries. It exposes the Prometheus HTTP API +under /api/v1/ with OpenStack authentication. + +Example to Create a Metric Service Client + + metricClient, err := openstack.NewMetricV1(ctx, providerClient, gophercloud.EndpointOpts{ + Region: "RegionOne", + }) + if err != nil { + panic(err) + } + +Example to Query Metrics + + opts := metrics.QueryOpts{ + Query: "up", + } + + result, err := metrics.Query(ctx, metricClient, opts).Extract() + if err != nil { + panic(err) + } + + for _, v := range result.Result { + fmt.Printf("%s: %v\n", v.Metric["__name__"], v.Value) + } + +Example to List Label Names + + labels, err := metrics.Labels(ctx, metricClient, nil).Extract() + if err != nil { + panic(err) + } + + for _, label := range labels { + fmt.Println(label) + } + +Example to Find Series by Label Matchers + + opts := metrics.SeriesOpts{ + Match: []string{"up", `process_start_time_seconds{job="prometheus"}`}, + } + + series, err := metrics.Series(ctx, metricClient, opts).Extract() + if err != nil { + panic(err) + } + + for _, s := range series { + fmt.Printf("%v\n", s) + } +*/ +package metrics diff --git a/openstack/metric/v1/metrics/requests.go b/openstack/metric/v1/metrics/requests.go new file mode 100644 index 0000000000..0fdc9624fb --- /dev/null +++ b/openstack/metric/v1/metrics/requests.go @@ -0,0 +1,263 @@ +package metrics + +import ( + "context" + + "github.com/gophercloud/gophercloud/v2" +) + +// QueryOptsBuilder allows extensions to add parameters to the Query request. +type QueryOptsBuilder interface { + ToMetricQueryQuery() (string, error) +} + +// QueryOpts contains the options for a Prometheus instant query. +type QueryOpts struct { + // Query is the PromQL query string. + Query string `q:"query" required:"true"` + + // Time is the evaluation timestamp (RFC3339 or Unix timestamp). + Time string `q:"time"` + + // Timeout is the evaluation timeout. + Timeout string `q:"timeout"` +} + +// ToMetricQueryQuery formats QueryOpts into a query string. +func (opts QueryOpts) ToMetricQueryQuery() (string, error) { + q, err := gophercloud.BuildQueryString(opts) + return q.String(), err +} + +// Query performs a Prometheus instant query. +func Query(ctx context.Context, client *gophercloud.ServiceClient, opts QueryOptsBuilder) (r QueryResult) { + url := queryURL(client) + if opts != nil { + query, err := opts.ToMetricQueryQuery() + if err != nil { + r.Err = err + return + } + url += query + } + resp, err := client.Get(ctx, url, &r.Body, nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + +// LabelsOptsBuilder allows extensions to add parameters to the Labels request. +type LabelsOptsBuilder interface { + ToMetricLabelsQuery() (string, error) +} + +// LabelsOpts contains the options for listing label names. +type LabelsOpts struct { + // Match is a list of series selectors to filter labels by. + Match []string `q:"match[]"` + + // Start is the start timestamp (RFC3339 or Unix timestamp). + Start string `q:"start"` + + // End is the end timestamp (RFC3339 or Unix timestamp). + End string `q:"end"` +} + +// ToMetricLabelsQuery formats LabelsOpts into a query string. +func (opts LabelsOpts) ToMetricLabelsQuery() (string, error) { + q, err := gophercloud.BuildQueryString(opts) + return q.String(), err +} + +// Labels returns a list of label names. +func Labels(ctx context.Context, client *gophercloud.ServiceClient, opts LabelsOptsBuilder) (r LabelsResult) { + url := labelsURL(client) + if opts != nil { + query, err := opts.ToMetricLabelsQuery() + if err != nil { + r.Err = err + return + } + url += query + } + resp, err := client.Get(ctx, url, &r.Body, nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + +// LabelValuesOptsBuilder allows extensions to add parameters to the LabelValues request. +type LabelValuesOptsBuilder interface { + ToMetricLabelValuesQuery() (string, error) +} + +// LabelValuesOpts contains the options for listing label values. +type LabelValuesOpts struct { + // Match is a list of series selectors to filter label values by. + Match []string `q:"match[]"` + + // Start is the start timestamp (RFC3339 or Unix timestamp). + Start string `q:"start"` + + // End is the end timestamp (RFC3339 or Unix timestamp). + End string `q:"end"` +} + +// ToMetricLabelValuesQuery formats LabelValuesOpts into a query string. +func (opts LabelValuesOpts) ToMetricLabelValuesQuery() (string, error) { + q, err := gophercloud.BuildQueryString(opts) + return q.String(), err +} + +// LabelValues returns a list of label values for a given label name. +func LabelValues(ctx context.Context, client *gophercloud.ServiceClient, name string, opts LabelValuesOptsBuilder) (r LabelValuesResult) { + url := labelValuesURL(client, name) + if opts != nil { + query, err := opts.ToMetricLabelValuesQuery() + if err != nil { + r.Err = err + return + } + url += query + } + resp, err := client.Get(ctx, url, &r.Body, nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + +// SeriesOptsBuilder allows extensions to add parameters to the Series request. +type SeriesOptsBuilder interface { + ToMetricSeriesQuery() (string, error) +} + +// SeriesOpts contains the options for finding series by label matchers. +type SeriesOpts struct { + // Match is a list of series selectors. At least one must be provided. + Match []string `q:"match[]" required:"true"` + + // Start is the start timestamp (RFC3339 or Unix timestamp). + Start string `q:"start"` + + // End is the end timestamp (RFC3339 or Unix timestamp). + End string `q:"end"` +} + +// ToMetricSeriesQuery formats SeriesOpts into a query string. +func (opts SeriesOpts) ToMetricSeriesQuery() (string, error) { + q, err := gophercloud.BuildQueryString(opts) + return q.String(), err +} + +// Series returns the list of time series that match certain label sets. +func Series(ctx context.Context, client *gophercloud.ServiceClient, opts SeriesOptsBuilder) (r SeriesResult) { + url := seriesURL(client) + if opts != nil { + query, err := opts.ToMetricSeriesQuery() + if err != nil { + r.Err = err + return + } + url += query + } + resp, err := client.Get(ctx, url, &r.Body, nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + +// TargetsOptsBuilder allows extensions to add parameters to the Targets request. +type TargetsOptsBuilder interface { + ToMetricTargetsQuery() (string, error) +} + +// TargetsOpts contains the options for listing targets. +type TargetsOpts struct { + // State filters targets by state ("active", "dropped", "any"). + State string `q:"state"` +} + +// ToMetricTargetsQuery formats TargetsOpts into a query string. +func (opts TargetsOpts) ToMetricTargetsQuery() (string, error) { + q, err := gophercloud.BuildQueryString(opts) + return q.String(), err +} + +// Targets returns an overview of the current state of Prometheus target discovery. +func Targets(ctx context.Context, client *gophercloud.ServiceClient, opts TargetsOptsBuilder) (r TargetsResult) { + url := targetsURL(client) + if opts != nil { + query, err := opts.ToMetricTargetsQuery() + if err != nil { + r.Err = err + return + } + url += query + } + resp, err := client.Get(ctx, url, &r.Body, nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + +// RuntimeInfo returns runtime information about the Prometheus server. +func RuntimeInfo(ctx context.Context, client *gophercloud.ServiceClient) (r RuntimeInfoResult) { + resp, err := client.Get(ctx, runtimeInfoURL(client), &r.Body, nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + +// CleanTombstones removes deleted data from disk and cleans up the existing tombstones. +func CleanTombstones(ctx context.Context, client *gophercloud.ServiceClient) (r CleanTombstonesResult) { + resp, err := client.Post(ctx, cleanTombstonesURL(client), nil, nil, &gophercloud.RequestOpts{ + OkCodes: []int{204}, + }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + +// DeleteSeriesOptsBuilder allows extensions to add parameters to the DeleteSeries request. +type DeleteSeriesOptsBuilder interface { + ToMetricDeleteSeriesQuery() (string, error) +} + +// DeleteSeriesOpts contains the options for deleting time series. +type DeleteSeriesOpts struct { + // Match is a list of series selectors. At least one must be provided. + Match []string `q:"match[]" required:"true"` + + // Start is the start timestamp (RFC3339 or Unix timestamp). + Start string `q:"start"` + + // End is the end timestamp (RFC3339 or Unix timestamp). + End string `q:"end"` +} + +// ToMetricDeleteSeriesQuery formats DeleteSeriesOpts into a query string. +func (opts DeleteSeriesOpts) ToMetricDeleteSeriesQuery() (string, error) { + q, err := gophercloud.BuildQueryString(opts) + return q.String(), err +} + +// DeleteSeries deletes data for a selection of series in a time range. +func DeleteSeries(ctx context.Context, client *gophercloud.ServiceClient, opts DeleteSeriesOptsBuilder) (r DeleteSeriesResult) { + url := deleteSeriesURL(client) + if opts != nil { + query, err := opts.ToMetricDeleteSeriesQuery() + if err != nil { + r.Err = err + return + } + url += query + } + resp, err := client.Post(ctx, url, nil, nil, &gophercloud.RequestOpts{ + OkCodes: []int{204}, + }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + +// Snapshot creates a snapshot of all current data into snapshots/- +// under the TSDB's data directory and returns the directory as response. +func Snapshot(ctx context.Context, client *gophercloud.ServiceClient) (r SnapshotResult) { + resp, err := client.Post(ctx, snapshotURL(client), nil, &r.Body, &gophercloud.RequestOpts{ + OkCodes: []int{200}, + }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} diff --git a/openstack/metric/v1/metrics/results.go b/openstack/metric/v1/metrics/results.go new file mode 100644 index 0000000000..c4c6463ecf --- /dev/null +++ b/openstack/metric/v1/metrics/results.go @@ -0,0 +1,298 @@ +package metrics + +import ( + "encoding/json" + "fmt" + + "github.com/gophercloud/gophercloud/v2" +) + +// prometheusResponse is the common envelope for all Prometheus HTTP API responses. +type prometheusResponse struct { + Status string `json:"status"` + Data json.RawMessage `json:"data"` + ErrorType string `json:"errorType"` + Error string `json:"error"` +} + +// checkResponse unmarshals the Prometheus envelope and returns an error if +// the response status is "error". +func checkResponse(body any) (*prometheusResponse, error) { + b, err := json.Marshal(body) + if err != nil { + return nil, err + } + var resp prometheusResponse + if err := json.Unmarshal(b, &resp); err != nil { + return nil, err + } + if resp.Status == "error" { + return &resp, fmt.Errorf("prometheus %s: %s", resp.ErrorType, resp.Error) + } + return &resp, nil +} + +// QueryResult is the result of a Query request. +type QueryResult struct { + gophercloud.Result +} + +// Extract interprets a QueryResult as QueryData. +func (r QueryResult) Extract() (*QueryData, error) { + if r.Err != nil { + return nil, r.Err + } + resp, err := checkResponse(r.Body) + if err != nil { + return nil, err + } + var data QueryData + if err := json.Unmarshal(resp.Data, &data); err != nil { + return nil, err + } + return &data, nil +} + +// LabelsResult is the result of a Labels request. +type LabelsResult struct { + gophercloud.Result +} + +// Extract interprets a LabelsResult as a slice of label name strings. +func (r LabelsResult) Extract() ([]string, error) { + if r.Err != nil { + return nil, r.Err + } + resp, err := checkResponse(r.Body) + if err != nil { + return nil, err + } + var data []string + if err := json.Unmarshal(resp.Data, &data); err != nil { + return nil, err + } + return data, nil +} + +// LabelValuesResult is the result of a LabelValues request. +type LabelValuesResult struct { + gophercloud.Result +} + +// Extract interprets a LabelValuesResult as a slice of label value strings. +func (r LabelValuesResult) Extract() ([]string, error) { + if r.Err != nil { + return nil, r.Err + } + resp, err := checkResponse(r.Body) + if err != nil { + return nil, err + } + var data []string + if err := json.Unmarshal(resp.Data, &data); err != nil { + return nil, err + } + return data, nil +} + +// SeriesResult is the result of a Series request. +type SeriesResult struct { + gophercloud.Result +} + +// Extract interprets a SeriesResult as a slice of label-set maps. +func (r SeriesResult) Extract() ([]map[string]string, error) { + if r.Err != nil { + return nil, r.Err + } + resp, err := checkResponse(r.Body) + if err != nil { + return nil, err + } + var data []map[string]string + if err := json.Unmarshal(resp.Data, &data); err != nil { + return nil, err + } + return data, nil +} + +// TargetsResult is the result of a Targets request. +type TargetsResult struct { + gophercloud.Result +} + +// Extract interprets a TargetsResult as TargetsData. +func (r TargetsResult) Extract() (*TargetsData, error) { + if r.Err != nil { + return nil, r.Err + } + resp, err := checkResponse(r.Body) + if err != nil { + return nil, err + } + var data TargetsData + if err := json.Unmarshal(resp.Data, &data); err != nil { + return nil, err + } + return &data, nil +} + +// RuntimeInfoResult is the result of a RuntimeInfo request. +type RuntimeInfoResult struct { + gophercloud.Result +} + +// Extract interprets a RuntimeInfoResult as RuntimeInfoData. +func (r RuntimeInfoResult) Extract() (*RuntimeInfoData, error) { + if r.Err != nil { + return nil, r.Err + } + resp, err := checkResponse(r.Body) + if err != nil { + return nil, err + } + var data RuntimeInfoData + if err := json.Unmarshal(resp.Data, &data); err != nil { + return nil, err + } + return &data, nil +} + +// CleanTombstonesResult is the result of a CleanTombstones request. +type CleanTombstonesResult struct { + gophercloud.ErrResult +} + +// DeleteSeriesResult is the result of a DeleteSeries request. +type DeleteSeriesResult struct { + gophercloud.ErrResult +} + +// SnapshotResult is the result of a Snapshot request. +type SnapshotResult struct { + gophercloud.Result +} + +// Extract interprets a SnapshotResult as SnapshotData. +func (r SnapshotResult) Extract() (*SnapshotData, error) { + if r.Err != nil { + return nil, r.Err + } + resp, err := checkResponse(r.Body) + if err != nil { + return nil, err + } + var data SnapshotData + if err := json.Unmarshal(resp.Data, &data); err != nil { + return nil, err + } + return &data, nil +} + +// QueryData represents the data field of a Prometheus instant query response. +type QueryData struct { + // ResultType is the type of result (e.g., "vector", "matrix", "scalar", "string"). + ResultType string `json:"resultType"` + + // Result is the list of metric values returned by the query. + Result []MetricValue `json:"result"` +} + +// MetricValue represents a single metric result with its labels and value. +type MetricValue struct { + // Metric contains the label set identifying this metric. + Metric map[string]string `json:"metric"` + + // Value contains a single sample value as [timestamp, "string_value"]. + Value []any `json:"value"` +} + +// TargetsData represents the data field of a Prometheus targets response. +type TargetsData struct { + // ActiveTargets is the list of currently active scrape targets. + ActiveTargets []ActiveTarget `json:"activeTargets"` + + // DroppedTargets is the list of targets that were dropped during relabeling. + DroppedTargets []DroppedTarget `json:"droppedTargets"` +} + +// ActiveTarget represents an active Prometheus scrape target. +type ActiveTarget struct { + // DiscoveredLabels are the unmodified labels from service discovery. + DiscoveredLabels map[string]string `json:"discoveredLabels"` + + // Labels are the labels after relabeling. + Labels map[string]string `json:"labels"` + + // ScrapePool is the name of the scrape configuration. + ScrapePool string `json:"scrapePool"` + + // ScrapeURL is the URL being scraped. + ScrapeURL string `json:"scrapeUrl"` + + // GlobalURL is the URL as available from other Prometheus instances. + GlobalURL string `json:"globalUrl"` + + // LastError is the last error encountered during scraping. + LastError string `json:"lastError"` + + // LastScrape is the time of the last scrape. + LastScrape string `json:"lastScrape"` + + // LastScrapeDuration is the duration of the last scrape in seconds. + LastScrapeDuration float64 `json:"lastScrapeDuration"` + + // Health is the health status of the target ("up", "down", "unknown"). + Health string `json:"health"` + + // ScrapeInterval is the configured scrape interval. + ScrapeInterval string `json:"scrapeInterval"` + + // ScrapeTimeout is the configured scrape timeout. + ScrapeTimeout string `json:"scrapeTimeout"` +} + +// DroppedTarget represents a target that was dropped during relabeling. +type DroppedTarget struct { + // DiscoveredLabels are the unmodified labels from service discovery. + DiscoveredLabels map[string]string `json:"discoveredLabels"` +} + +// RuntimeInfoData represents the data field of a Prometheus runtime info response. +type RuntimeInfoData struct { + // StartTime is when the Prometheus server started. + StartTime string `json:"startTime"` + + // CWD is the current working directory of the Prometheus server. + CWD string `json:"CWD"` + + // ReloadConfigSuccess indicates if the last config reload was successful. + ReloadConfigSuccess bool `json:"reloadConfigSuccess"` + + // LastConfigTime is the time of the last config reload. + LastConfigTime string `json:"lastConfigTime"` + + // CorruptionCount is the number of WAL corruptions encountered. + CorruptionCount int `json:"corruptionCount"` + + // GoroutineCount is the number of goroutines. + GoroutineCount int `json:"goroutineCount"` + + // GOMAXPROCS is the configured GOMAXPROCS value. + GOMAXPROCS int `json:"GOMAXPROCS"` + + // GOGC is the configured GOGC value. + GOGC string `json:"GOGC"` + + // GODEBUG is the configured GODEBUG value. + GODEBUG string `json:"GODEBUG"` + + // StorageRetention is the configured storage retention. + StorageRetention string `json:"storageRetention"` +} + +// SnapshotData represents the data field of a Prometheus snapshot response. +type SnapshotData struct { + // Name is the filename of the snapshot created. + Name string `json:"name"` +} diff --git a/openstack/metric/v1/metrics/testing/doc.go b/openstack/metric/v1/metrics/testing/doc.go new file mode 100644 index 0000000000..c1ca16c942 --- /dev/null +++ b/openstack/metric/v1/metrics/testing/doc.go @@ -0,0 +1,2 @@ +// metrics unit tests +package testing diff --git a/openstack/metric/v1/metrics/testing/fixtures_test.go b/openstack/metric/v1/metrics/testing/fixtures_test.go new file mode 100644 index 0000000000..7da259fc61 --- /dev/null +++ b/openstack/metric/v1/metrics/testing/fixtures_test.go @@ -0,0 +1,327 @@ +package testing + +import ( + "fmt" + "net/http" + "testing" + + "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/openstack/metric/v1/metrics" + th "github.com/gophercloud/gophercloud/v2/testhelper" + "github.com/gophercloud/gophercloud/v2/testhelper/client" +) + +// serviceClient returns a ServiceClient with ResourceBase set to include api/v1/. +func serviceClient(fakeServer th.FakeServer) *gophercloud.ServiceClient { + sc := client.ServiceClient(fakeServer) + sc.ResourceBase = sc.Endpoint + "api/v1/" + return sc +} + +// QueryOutput is a sample response to a Query call. +const QueryOutput = ` +{ + "status": "success", + "data": { + "resultType": "vector", + "result": [ + { + "metric": { + "__name__": "up", + "instance": "localhost:9090", + "job": "prometheus" + }, + "value": [1435781451.781, "1"] + } + ] + } +} +` + +// ExpectedQueryData is the expected result from QueryOutput. +var ExpectedQueryData = &metrics.QueryData{ + ResultType: "vector", + Result: []metrics.MetricValue{ + { + Metric: map[string]string{ + "__name__": "up", + "instance": "localhost:9090", + "job": "prometheus", + }, + Value: []any{1435781451.781, "1"}, + }, + }, +} + +// LabelsOutput is a sample response to a Labels call. +const LabelsOutput = ` +{ + "status": "success", + "data": ["__name__", "instance", "job"] +} +` + +// ExpectedLabels is the expected result from LabelsOutput. +var ExpectedLabels = []string{"__name__", "instance", "job"} + +// LabelValuesOutput is a sample response to a LabelValues call. +const LabelValuesOutput = ` +{ + "status": "success", + "data": ["node", "prometheus"] +} +` + +// ExpectedLabelValues is the expected result from LabelValuesOutput. +var ExpectedLabelValues = []string{"node", "prometheus"} + +// SeriesOutput is a sample response to a Series call. +const SeriesOutput = ` +{ + "status": "success", + "data": [ + { + "__name__": "up", + "instance": "localhost:9090", + "job": "prometheus" + }, + { + "__name__": "up", + "instance": "localhost:9100", + "job": "node" + } + ] +} +` + +// ExpectedSeries is the expected result from SeriesOutput. +var ExpectedSeries = []map[string]string{ + { + "__name__": "up", + "instance": "localhost:9090", + "job": "prometheus", + }, + { + "__name__": "up", + "instance": "localhost:9100", + "job": "node", + }, +} + +// TargetsOutput is a sample response to a Targets call. +const TargetsOutput = ` +{ + "status": "success", + "data": { + "activeTargets": [ + { + "discoveredLabels": { + "__address__": "localhost:9090", + "__scheme__": "http", + "job": "prometheus" + }, + "labels": { + "instance": "localhost:9090", + "job": "prometheus" + }, + "scrapePool": "prometheus", + "scrapeUrl": "http://localhost:9090/metrics", + "globalUrl": "http://localhost:9090/metrics", + "lastError": "", + "lastScrape": "2025-08-20T10:30:00.000Z", + "lastScrapeDuration": 0.003145, + "health": "up", + "scrapeInterval": "15s", + "scrapeTimeout": "10s" + } + ], + "droppedTargets": [ + { + "discoveredLabels": { + "__address__": "localhost:9091", + "job": "dropped" + } + } + ] + } +} +` + +// ExpectedTargetsData is the expected result from TargetsOutput. +var ExpectedTargetsData = &metrics.TargetsData{ + ActiveTargets: []metrics.ActiveTarget{ + { + DiscoveredLabels: map[string]string{ + "__address__": "localhost:9090", + "__scheme__": "http", + "job": "prometheus", + }, + Labels: map[string]string{ + "instance": "localhost:9090", + "job": "prometheus", + }, + ScrapePool: "prometheus", + ScrapeURL: "http://localhost:9090/metrics", + GlobalURL: "http://localhost:9090/metrics", + LastError: "", + LastScrape: "2025-08-20T10:30:00.000Z", + LastScrapeDuration: 0.003145, + Health: "up", + ScrapeInterval: "15s", + ScrapeTimeout: "10s", + }, + }, + DroppedTargets: []metrics.DroppedTarget{ + { + DiscoveredLabels: map[string]string{ + "__address__": "localhost:9091", + "job": "dropped", + }, + }, + }, +} + +// RuntimeInfoOutput is a sample response to a RuntimeInfo call. +const RuntimeInfoOutput = ` +{ + "status": "success", + "data": { + "startTime": "2025-08-20T10:00:00.000Z", + "CWD": "/prometheus", + "reloadConfigSuccess": true, + "lastConfigTime": "2025-08-20T10:00:00.000Z", + "corruptionCount": 0, + "goroutineCount": 42, + "GOMAXPROCS": 4, + "GOGC": "", + "GODEBUG": "", + "storageRetention": "15d" + } +} +` + +// ExpectedRuntimeInfoData is the expected result from RuntimeInfoOutput. +var ExpectedRuntimeInfoData = &metrics.RuntimeInfoData{ + StartTime: "2025-08-20T10:00:00.000Z", + CWD: "/prometheus", + ReloadConfigSuccess: true, + LastConfigTime: "2025-08-20T10:00:00.000Z", + CorruptionCount: 0, + GoroutineCount: 42, + GOMAXPROCS: 4, + GOGC: "", + GODEBUG: "", + StorageRetention: "15d", +} + +// SnapshotOutput is a sample response to a Snapshot call. +const SnapshotOutput = ` +{ + "status": "success", + "data": { + "name": "20250820T100000Z-abcdef1234567890" + } +} +` + +// ExpectedSnapshotData is the expected result from SnapshotOutput. +var ExpectedSnapshotData = &metrics.SnapshotData{ + Name: "20250820T100000Z-abcdef1234567890", +} + +// HandleQuerySuccessfully configures the test server to respond to a Query request. +func HandleQuerySuccessfully(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/api/v1/query", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + fmt.Fprint(w, QueryOutput) + }) +} + +// HandleLabelsSuccessfully configures the test server to respond to a Labels request. +func HandleLabelsSuccessfully(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/api/v1/labels", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + fmt.Fprint(w, LabelsOutput) + }) +} + +// HandleLabelValuesSuccessfully configures the test server to respond to a LabelValues request. +func HandleLabelValuesSuccessfully(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/api/v1/label/job/values", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + fmt.Fprint(w, LabelValuesOutput) + }) +} + +// HandleSeriesSuccessfully configures the test server to respond to a Series request. +func HandleSeriesSuccessfully(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/api/v1/series", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + fmt.Fprint(w, SeriesOutput) + }) +} + +// HandleTargetsSuccessfully configures the test server to respond to a Targets request. +func HandleTargetsSuccessfully(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/api/v1/targets", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + fmt.Fprint(w, TargetsOutput) + }) +} + +// HandleRuntimeInfoSuccessfully configures the test server to respond to a RuntimeInfo request. +func HandleRuntimeInfoSuccessfully(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/api/v1/status/runtimeinfo", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + fmt.Fprint(w, RuntimeInfoOutput) + }) +} + +// HandleCleanTombstonesSuccessfully configures the test server to respond to a CleanTombstones request. +func HandleCleanTombstonesSuccessfully(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/api/v1/admin/tsdb/clean_tombstones", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.WriteHeader(http.StatusNoContent) + }) +} + +// HandleDeleteSeriesSuccessfully configures the test server to respond to a DeleteSeries request. +func HandleDeleteSeriesSuccessfully(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/api/v1/admin/tsdb/delete_series", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.WriteHeader(http.StatusNoContent) + }) +} + +// HandleSnapshotSuccessfully configures the test server to respond to a Snapshot request. +func HandleSnapshotSuccessfully(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/api/v1/admin/tsdb/snapshot", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + fmt.Fprint(w, SnapshotOutput) + }) +} diff --git a/openstack/metric/v1/metrics/testing/requests_test.go b/openstack/metric/v1/metrics/testing/requests_test.go new file mode 100644 index 0000000000..3311250643 --- /dev/null +++ b/openstack/metric/v1/metrics/testing/requests_test.go @@ -0,0 +1,109 @@ +package testing + +import ( + "context" + "testing" + + "github.com/gophercloud/gophercloud/v2/openstack/metric/v1/metrics" + th "github.com/gophercloud/gophercloud/v2/testhelper" +) + +func TestQuery(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + HandleQuerySuccessfully(t, fakeServer) + + opts := metrics.QueryOpts{ + Query: "up", + } + + actual, err := metrics.Query(context.TODO(), serviceClient(fakeServer), opts).Extract() + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, ExpectedQueryData, actual) +} + +func TestLabels(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + HandleLabelsSuccessfully(t, fakeServer) + + actual, err := metrics.Labels(context.TODO(), serviceClient(fakeServer), nil).Extract() + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, ExpectedLabels, actual) +} + +func TestLabelValues(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + HandleLabelValuesSuccessfully(t, fakeServer) + + actual, err := metrics.LabelValues(context.TODO(), serviceClient(fakeServer), "job", nil).Extract() + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, ExpectedLabelValues, actual) +} + +func TestSeries(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + HandleSeriesSuccessfully(t, fakeServer) + + opts := metrics.SeriesOpts{ + Match: []string{"up"}, + } + + actual, err := metrics.Series(context.TODO(), serviceClient(fakeServer), opts).Extract() + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, ExpectedSeries, actual) +} + +func TestTargets(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + HandleTargetsSuccessfully(t, fakeServer) + + actual, err := metrics.Targets(context.TODO(), serviceClient(fakeServer), nil).Extract() + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, ExpectedTargetsData, actual) +} + +func TestRuntimeInfo(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + HandleRuntimeInfoSuccessfully(t, fakeServer) + + actual, err := metrics.RuntimeInfo(context.TODO(), serviceClient(fakeServer)).Extract() + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, ExpectedRuntimeInfoData, actual) +} + +func TestCleanTombstones(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + HandleCleanTombstonesSuccessfully(t, fakeServer) + + err := metrics.CleanTombstones(context.TODO(), serviceClient(fakeServer)).ExtractErr() + th.AssertNoErr(t, err) +} + +func TestDeleteSeries(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + HandleDeleteSeriesSuccessfully(t, fakeServer) + + opts := metrics.DeleteSeriesOpts{ + Match: []string{"up"}, + } + + err := metrics.DeleteSeries(context.TODO(), serviceClient(fakeServer), opts).ExtractErr() + th.AssertNoErr(t, err) +} + +func TestSnapshot(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + HandleSnapshotSuccessfully(t, fakeServer) + + actual, err := metrics.Snapshot(context.TODO(), serviceClient(fakeServer)).Extract() + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, ExpectedSnapshotData, actual) +} diff --git a/openstack/metric/v1/metrics/urls.go b/openstack/metric/v1/metrics/urls.go new file mode 100644 index 0000000000..856f84da5b --- /dev/null +++ b/openstack/metric/v1/metrics/urls.go @@ -0,0 +1,39 @@ +package metrics + +import "github.com/gophercloud/gophercloud/v2" + +func queryURL(c *gophercloud.ServiceClient) string { + return c.ServiceURL("query") +} + +func labelsURL(c *gophercloud.ServiceClient) string { + return c.ServiceURL("labels") +} + +func labelValuesURL(c *gophercloud.ServiceClient, name string) string { + return c.ServiceURL("label", name, "values") +} + +func seriesURL(c *gophercloud.ServiceClient) string { + return c.ServiceURL("series") +} + +func targetsURL(c *gophercloud.ServiceClient) string { + return c.ServiceURL("targets") +} + +func runtimeInfoURL(c *gophercloud.ServiceClient) string { + return c.ServiceURL("status", "runtimeinfo") +} + +func cleanTombstonesURL(c *gophercloud.ServiceClient) string { + return c.ServiceURL("admin", "tsdb", "clean_tombstones") +} + +func deleteSeriesURL(c *gophercloud.ServiceClient) string { + return c.ServiceURL("admin", "tsdb", "delete_series") +} + +func snapshotURL(c *gophercloud.ServiceClient) string { + return c.ServiceURL("admin", "tsdb", "snapshot") +} From 754152282466de0efdfc7b2a7b7176d5b30e064c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Wed, 8 Apr 2026 11:14:20 +0200 Subject: [PATCH 361/429] ci: configure dependabot to target both main and v2 branches --- .github/dependabot.yaml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml index b061387fea..83e79253ce 100644 --- a/.github/dependabot.yaml +++ b/.github/dependabot.yaml @@ -2,6 +2,7 @@ version: 2 updates: - package-ecosystem: gomod directory: "/" + target-branch: "main" schedule: interval: daily cooldown: @@ -9,6 +10,23 @@ updates: open-pull-requests-limit: 10 - package-ecosystem: "github-actions" directory: "/" + target-branch: "main" + schedule: + interval: daily + cooldown: + default-days: 7 + open-pull-requests-limit: 10 +- package-ecosystem: gomod + directory: "/" + target-branch: "v2" + schedule: + interval: daily + cooldown: + default-days: 7 + open-pull-requests-limit: 10 +- package-ecosystem: "github-actions" + directory: "/" + target-branch: "v2" schedule: interval: daily cooldown: From 5dfe40e243a1dce4cecf4d4cffc1c29c02ab2eb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Wed, 8 Apr 2026 11:18:03 +0200 Subject: [PATCH 362/429] ci: skip backporting PRs with the dependencies label --- .github/workflows/backport.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/backport.yaml b/.github/workflows/backport.yaml index ba02bce85b..db5bc27aeb 100644 --- a/.github/workflows/backport.yaml +++ b/.github/workflows/backport.yaml @@ -19,6 +19,7 @@ jobs: # See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target. if: > github.event.pull_request.merged + && !contains(github.event.pull_request.labels.*.name, 'dependencies') && ( github.event.action == 'closed' && contains(github.event.pull_request.labels.*.name, 'backport-v1') @@ -84,6 +85,7 @@ jobs: # See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target. if: > github.event.pull_request.merged + && !contains(github.event.pull_request.labels.*.name, 'dependencies') && ( github.event.action == 'closed' && contains(github.event.pull_request.labels.*.name, 'backport-v2') From 52045f730156d7f246ebd8429161fa6b4b28fb2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Wed, 8 Apr 2026 12:20:25 +0200 Subject: [PATCH 363/429] ci: use exact release tags in GitHub Actions version comments Replace floating major version comments (e.g. # v6, # v2, # v1) with exact release tags matching each pinned SHA, and add missing version comments. This makes it easier to track which version is actually in use. --- .github/workflows/backport.yaml | 4 ++-- .github/workflows/codeql-analysis.yaml | 10 +++++----- .github/workflows/ensure-labels.yaml | 4 ++-- .github/workflows/functional-baremetal.yaml | 4 ++-- .github/workflows/functional-basic.yaml | 4 ++-- .github/workflows/functional-blockstorage.yaml | 4 ++-- .github/workflows/functional-compute.yaml | 4 ++-- .github/workflows/functional-containerinfra.yaml | 4 ++-- .github/workflows/functional-dns.yaml | 4 ++-- .github/workflows/functional-fwaas_v2.yaml | 4 ++-- .github/workflows/functional-identity.yaml | 4 ++-- .github/workflows/functional-image.yaml | 4 ++-- .github/workflows/functional-keymanager.yaml | 4 ++-- .github/workflows/functional-loadbalancer.yaml | 4 ++-- .github/workflows/functional-messaging.yaml | 4 ++-- .github/workflows/functional-metric.yaml | 4 ++-- .github/workflows/functional-networking.yaml | 4 ++-- .github/workflows/functional-objectstorage.yaml | 4 ++-- .github/workflows/functional-orchestration.yaml | 4 ++-- .github/workflows/functional-placement.yaml | 4 ++-- .github/workflows/functional-sharedfilesystems.yaml | 4 ++-- .github/workflows/functional-workflow.yaml | 4 ++-- .github/workflows/label-pr.yaml | 2 +- .github/workflows/lint.yaml | 4 ++-- .github/workflows/semver.yaml | 4 ++-- .github/workflows/unit.yaml | 8 ++++---- .github/workflows/zizmor.yaml | 2 +- 27 files changed, 57 insertions(+), 57 deletions(-) diff --git a/.github/workflows/backport.yaml b/.github/workflows/backport.yaml index db5bc27aeb..7e23e840f4 100644 --- a/.github/workflows/backport.yaml +++ b/.github/workflows/backport.yaml @@ -32,7 +32,7 @@ jobs: steps: - name: Generate a token from the gophercloud-backport-bot github-app id: generate_token - uses: getsentry/action-github-app-token@a0061014b82a6a5d6aeeb3b824aced47e3c3a7ef + uses: getsentry/action-github-app-token@5c1e90706fe007857338ac1bfbd7a4177db2f789 # v4.0.0 with: app_id: ${{ secrets.BACKPORT_APP_ID }} # zizmor: ignore[secrets-outside-env] private_key: ${{ secrets.BACKPORT_APP_PRIVATE_KEY }} # zizmor: ignore[secrets-outside-env] @@ -98,7 +98,7 @@ jobs: steps: - name: Generate a token from the gophercloud-backport-bot github-app id: generate_token - uses: getsentry/action-github-app-token@a0061014b82a6a5d6aeeb3b824aced47e3c3a7ef + uses: getsentry/action-github-app-token@5c1e90706fe007857338ac1bfbd7a4177db2f789 # v4.0.0 with: app_id: ${{ secrets.BACKPORT_APP_ID }} # zizmor: ignore[secrets-outside-env] private_key: ${{ secrets.BACKPORT_APP_PRIVATE_KEY }} # zizmor: ignore[secrets-outside-env] diff --git a/.github/workflows/codeql-analysis.yaml b/.github/workflows/codeql-analysis.yaml index 3d11b8f50a..a445b45fc9 100644 --- a/.github/workflows/codeql-analysis.yaml +++ b/.github/workflows/codeql-analysis.yaml @@ -18,23 +18,23 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - name: Setup Go - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version-file: 'go.mod' cache: true - name: Initialize CodeQL - uses: github/codeql-action/init@c10b8064de6f491fea524254123dbe5e09572f13 # v4 + uses: github/codeql-action/init@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@c10b8064de6f491fea524254123dbe5e09572f13 # v4 + uses: github/codeql-action/autobuild@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@c10b8064de6f491fea524254123dbe5e09572f13 # v4 + uses: github/codeql-action/analyze@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1 diff --git a/.github/workflows/ensure-labels.yaml b/.github/workflows/ensure-labels.yaml index bb92db737b..4df98ce2bc 100644 --- a/.github/workflows/ensure-labels.yaml +++ b/.github/workflows/ensure-labels.yaml @@ -13,10 +13,10 @@ jobs: issues: write runs-on: ubuntu-latest steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - - uses: micnncim/action-label-syncer@3abd5ab72fda571e69fffd97bd4e0033dd5f495c # v1 + - uses: micnncim/action-label-syncer@3abd5ab72fda571e69fffd97bd4e0033dd5f495c # v1.3.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: diff --git a/.github/workflows/functional-baremetal.yaml b/.github/workflows/functional-baremetal.yaml index 7248cbf947..1aabed3a50 100644 --- a/.github/workflows/functional-baremetal.yaml +++ b/.github/workflows/functional-baremetal.yaml @@ -25,7 +25,7 @@ jobs: name: Ironic on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -101,7 +101,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-basic.yaml b/.github/workflows/functional-basic.yaml index 313d67c2d3..ee9da6e81c 100644 --- a/.github/workflows/functional-basic.yaml +++ b/.github/workflows/functional-basic.yaml @@ -25,7 +25,7 @@ jobs: name: basic tests on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -55,7 +55,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-blockstorage.yaml b/.github/workflows/functional-blockstorage.yaml index f067e785ce..a931d13f06 100644 --- a/.github/workflows/functional-blockstorage.yaml +++ b/.github/workflows/functional-blockstorage.yaml @@ -25,7 +25,7 @@ jobs: name: Cinder on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -61,7 +61,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-compute.yaml b/.github/workflows/functional-compute.yaml index b2d2f27701..d280e8f328 100644 --- a/.github/workflows/functional-compute.yaml +++ b/.github/workflows/functional-compute.yaml @@ -25,7 +25,7 @@ jobs: name: Nova on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -61,7 +61,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-containerinfra.yaml b/.github/workflows/functional-containerinfra.yaml index 8edabce192..db4122cc9b 100644 --- a/.github/workflows/functional-containerinfra.yaml +++ b/.github/workflows/functional-containerinfra.yaml @@ -46,7 +46,7 @@ jobs: name: Magnum on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -88,7 +88,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-dns.yaml b/.github/workflows/functional-dns.yaml index 5ad1d8771f..956b0c16da 100644 --- a/.github/workflows/functional-dns.yaml +++ b/.github/workflows/functional-dns.yaml @@ -31,7 +31,7 @@ jobs: name: Designate on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -69,7 +69,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-fwaas_v2.yaml b/.github/workflows/functional-fwaas_v2.yaml index 97cbb3f716..41559bd9eb 100644 --- a/.github/workflows/functional-fwaas_v2.yaml +++ b/.github/workflows/functional-fwaas_v2.yaml @@ -29,7 +29,7 @@ jobs: name: FWaaS_v2 on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -84,7 +84,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-identity.yaml b/.github/workflows/functional-identity.yaml index 651e59bc3d..6f9a1d1340 100644 --- a/.github/workflows/functional-identity.yaml +++ b/.github/workflows/functional-identity.yaml @@ -25,7 +25,7 @@ jobs: name: Keystone on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -59,7 +59,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-image.yaml b/.github/workflows/functional-image.yaml index e9e688044d..980fbf7e02 100644 --- a/.github/workflows/functional-image.yaml +++ b/.github/workflows/functional-image.yaml @@ -25,7 +25,7 @@ jobs: name: Glance on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -59,7 +59,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-keymanager.yaml b/.github/workflows/functional-keymanager.yaml index e312e034a0..aad940ca9b 100644 --- a/.github/workflows/functional-keymanager.yaml +++ b/.github/workflows/functional-keymanager.yaml @@ -37,7 +37,7 @@ jobs: name: Barbican on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -75,7 +75,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-loadbalancer.yaml b/.github/workflows/functional-loadbalancer.yaml index 8a80c2ea5e..e3c24ee6c9 100644 --- a/.github/workflows/functional-loadbalancer.yaml +++ b/.github/workflows/functional-loadbalancer.yaml @@ -36,7 +36,7 @@ jobs: name: Octavia on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -75,7 +75,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-messaging.yaml b/.github/workflows/functional-messaging.yaml index 3aba20dd6f..c7b27e8058 100644 --- a/.github/workflows/functional-messaging.yaml +++ b/.github/workflows/functional-messaging.yaml @@ -25,7 +25,7 @@ jobs: name: Zaqar on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -62,7 +62,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-metric.yaml b/.github/workflows/functional-metric.yaml index 8f60039792..6178579e6e 100644 --- a/.github/workflows/functional-metric.yaml +++ b/.github/workflows/functional-metric.yaml @@ -25,7 +25,7 @@ jobs: name: Aetos on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -68,7 +68,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-networking.yaml b/.github/workflows/functional-networking.yaml index b93e3c1f2c..eab70110b7 100644 --- a/.github/workflows/functional-networking.yaml +++ b/.github/workflows/functional-networking.yaml @@ -25,7 +25,7 @@ jobs: name: Neutron on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -79,7 +79,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-objectstorage.yaml b/.github/workflows/functional-objectstorage.yaml index 2b3db097d0..07c29a7438 100644 --- a/.github/workflows/functional-objectstorage.yaml +++ b/.github/workflows/functional-objectstorage.yaml @@ -25,7 +25,7 @@ jobs: name: Swift on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -65,7 +65,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-orchestration.yaml b/.github/workflows/functional-orchestration.yaml index dbd5d36668..8396b954fb 100644 --- a/.github/workflows/functional-orchestration.yaml +++ b/.github/workflows/functional-orchestration.yaml @@ -25,7 +25,7 @@ jobs: name: Heat on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -61,7 +61,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-placement.yaml b/.github/workflows/functional-placement.yaml index 641b22e9bc..99fa2615c7 100644 --- a/.github/workflows/functional-placement.yaml +++ b/.github/workflows/functional-placement.yaml @@ -25,7 +25,7 @@ jobs: name: Placement on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -59,7 +59,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-sharedfilesystems.yaml b/.github/workflows/functional-sharedfilesystems.yaml index e8fc1a03a6..928f297b24 100644 --- a/.github/workflows/functional-sharedfilesystems.yaml +++ b/.github/workflows/functional-sharedfilesystems.yaml @@ -31,7 +31,7 @@ jobs: name: Manila on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -83,7 +83,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/functional-workflow.yaml b/.github/workflows/functional-workflow.yaml index bb57db4067..77ec801634 100644 --- a/.github/workflows/functional-workflow.yaml +++ b/.github/workflows/functional-workflow.yaml @@ -28,7 +28,7 @@ jobs: name: Mistral on Deploy OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false @@ -64,7 +64,7 @@ jobs: - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/label-pr.yaml b/.github/workflows/label-pr.yaml index de5d9a52b0..882a879b13 100644 --- a/.github/workflows/label-pr.yaml +++ b/.github/workflows/label-pr.yaml @@ -109,4 +109,4 @@ jobs: contents: read pull-requests: write steps: - - uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6 + - uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6.0.1 diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 88784d2215..37108b22f2 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -10,10 +10,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 + - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/semver.yaml b/.github/workflows/semver.yaml index af9ff9643d..9e7133b525 100644 --- a/.github/workflows/semver.yaml +++ b/.github/workflows/semver.yaml @@ -13,7 +13,7 @@ jobs: analyze: runs-on: ubuntu-latest steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 ref: ${{ github.event.pull_request.head.sha }} @@ -28,7 +28,7 @@ jobs: GIT_SEQUENCE_EDITOR: '/usr/bin/true' BASE_REF: ${{ github.base_ref }} - - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 + - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version-file: 'go.mod' cache: true diff --git a/.github/workflows/unit.yaml b/.github/workflows/unit.yaml index fd82541b38..69b5466ee5 100644 --- a/.github/workflows/unit.yaml +++ b/.github/workflows/unit.yaml @@ -15,11 +15,11 @@ jobs: fail-fast: false steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - name: Setup Go - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 with: go-version-file: 'go.mod' cache: true @@ -34,7 +34,7 @@ jobs: make unit make coverage - name: Check coverage - uses: coverallsapp/github-action@5cbfd81b66ca5d10c19b062c04de0199c215fb6e # v2 + uses: coverallsapp/github-action@5cbfd81b66ca5d10c19b062c04de0199c215fb6e # v2.3.7 with: file: cover.out parallel: true @@ -46,6 +46,6 @@ jobs: runs-on: ubuntu-latest steps: - name: Store coverage results - uses: coverallsapp/github-action@5cbfd81b66ca5d10c19b062c04de0199c215fb6e # v2 + uses: coverallsapp/github-action@5cbfd81b66ca5d10c19b062c04de0199c215fb6e # v2.3.7 with: parallel-finished: true diff --git a/.github/workflows/zizmor.yaml b/.github/workflows/zizmor.yaml index e9b06d69ac..0a0fb0f41a 100644 --- a/.github/workflows/zizmor.yaml +++ b/.github/workflows/zizmor.yaml @@ -20,7 +20,7 @@ jobs: contents: read steps: - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false From 817740a329e59d90c08b1abcc857b3e6a4214e83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Wed, 8 Apr 2026 13:53:23 +0200 Subject: [PATCH 364/429] CI: prefer github mirrors whenever possible Our CI runs in github infra, let's use code that's already in github if we can. --- .github/workflows/functional-fwaas_v2.yaml | 2 +- .github/workflows/functional-metric.yaml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/functional-fwaas_v2.yaml b/.github/workflows/functional-fwaas_v2.yaml index 97cbb3f716..39598b2530 100644 --- a/.github/workflows/functional-fwaas_v2.yaml +++ b/.github/workflows/functional-fwaas_v2.yaml @@ -70,7 +70,7 @@ jobs: with: branch: ${{ matrix.openstack_version }} conf_overrides: | - enable_plugin neutron-fwaas https://opendev.org/openstack/neutron-fwaas ${{ matrix.openstack_version }} + enable_plugin neutron-fwaas https://github.com/openstack/neutron-fwaas ${{ matrix.openstack_version }} Q_AGENT=openvswitch Q_ML2_PLUGIN_MECHANISM_DRIVERS=openvswitch,l2population Q_ML2_PLUGIN_TYPE_DRIVERS=flat,gre,vlan,vxlan diff --git a/.github/workflows/functional-metric.yaml b/.github/workflows/functional-metric.yaml index 8f60039792..71cae7d6bc 100644 --- a/.github/workflows/functional-metric.yaml +++ b/.github/workflows/functional-metric.yaml @@ -56,12 +56,12 @@ jobs: with: branch: ${{ matrix.openstack_version }} conf_overrides: | - enable_plugin devstack-plugin-prometheus https://opendev.org/openstack/devstack-plugin-prometheus ${{ matrix.openstack_version }} - enable_plugin ceilometer https://opendev.org/openstack/ceilometer ${{ matrix.openstack_version }} + enable_plugin devstack-plugin-prometheus https://github.com/openstack/devstack-plugin-prometheus ${{ matrix.openstack_version }} + enable_plugin ceilometer https://github.com/openstack/ceilometer ${{ matrix.openstack_version }} CEILOMETER_BACKEND=sg-core PROMETHEUS_CUSTOM_SCRAPE_TARGETS="localhost:3000" enable_plugin sg-core https://github.com/openstack-k8s-operators/sg-core main - enable_plugin aetos https://opendev.org/openstack/aetos ${{ matrix.openstack_version }} + enable_plugin aetos https://github.com/openstack/aetos ${{ matrix.openstack_version }} ${{ matrix.devstack_conf_overrides }} enabled_services: "prometheus,node_exporter,openstack_exporter,ceilometer-acompute,ceilometer-acentral,ceilometer-anotification,sg-core,aetos,openstack-cli-server" From 15c319c3c7d0671dfa7e4a306c0ebf60625b9926 Mon Sep 17 00:00:00 2001 From: Dominik Danelski Date: Wed, 8 Apr 2026 15:48:12 +0200 Subject: [PATCH 365/429] Implement Placement allocationcandidates Related #526 API reference: https://docs.openstack.org/api-ref/placement/#list-allocation-candidates Code reference: https://opendev.org/openstack/placement/src/branch/stable/2026.1/placement/handlers/allocation_candidate.py#L256-L304 Signed-off-by: Dominik Danelski --- .../placement/v1/allocationcandidates_test.go | 208 +++++++ .../placement/v1/allocationcandidates/doc.go | 58 ++ .../v1/allocationcandidates/microversions.go | 52 ++ .../v1/allocationcandidates/requests.go | 140 +++++ .../v1/allocationcandidates/results.go | 85 +++ .../v1/allocationcandidates/testing/doc.go | 1 + .../testing/fixtures_test.go | 578 ++++++++++++++++++ .../testing/requests_test.go | 140 +++++ .../placement/v1/allocationcandidates/urls.go | 9 + 9 files changed, 1271 insertions(+) create mode 100644 internal/acceptance/openstack/placement/v1/allocationcandidates_test.go create mode 100644 openstack/placement/v1/allocationcandidates/doc.go create mode 100644 openstack/placement/v1/allocationcandidates/microversions.go create mode 100644 openstack/placement/v1/allocationcandidates/requests.go create mode 100644 openstack/placement/v1/allocationcandidates/results.go create mode 100644 openstack/placement/v1/allocationcandidates/testing/doc.go create mode 100644 openstack/placement/v1/allocationcandidates/testing/fixtures_test.go create mode 100644 openstack/placement/v1/allocationcandidates/testing/requests_test.go create mode 100644 openstack/placement/v1/allocationcandidates/urls.go diff --git a/internal/acceptance/openstack/placement/v1/allocationcandidates_test.go b/internal/acceptance/openstack/placement/v1/allocationcandidates_test.go new file mode 100644 index 0000000000..2cfc4074ac --- /dev/null +++ b/internal/acceptance/openstack/placement/v1/allocationcandidates_test.go @@ -0,0 +1,208 @@ +//go:build acceptance || placement || allocationcandidates + +package v1 + +import ( + "context" + "slices" + "testing" + + "github.com/gophercloud/gophercloud/v2/internal/acceptance/clients" + "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" + "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/allocationcandidates" + "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/resourceproviders" + th "github.com/gophercloud/gophercloud/v2/testhelper" +) + +// createRPWithVCPUInventory creates a resource provider and seeds it with +// VCPU inventory, returning the provider UUID. The caller is responsible for +// deferring deletion of the provider. +func createRPWithVCPUInventory(t *testing.T, microversion string) (string, func()) { + t.Helper() + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + client.Microversion = microversion + + rp, err := CreateResourceProvider(t, client) + th.AssertNoErr(t, err) + + inventories, err := resourceproviders.GetInventories(context.TODO(), client, rp.UUID).Extract() + th.AssertNoErr(t, err) + + inventories, err = resourceproviders.UpdateInventories(context.TODO(), client, rp.UUID, resourceproviders.UpdateInventoriesOpts{ + ResourceProviderGeneration: inventories.ResourceProviderGeneration, + Inventories: map[string]resourceproviders.Inventory{ + "VCPU": { + AllocationRatio: 1.0, + MaxUnit: 8, + MinUnit: 1, + Reserved: 0, + StepSize: 1, + Total: 8, + }, + }, + }).Extract() + th.AssertNoErr(t, err) + + _, err = resourceproviders.UpdateTraits(context.TODO(), client, rp.UUID, resourceproviders.UpdateTraitsOpts{ + ResourceProviderGeneration: inventories.ResourceProviderGeneration, + Traits: []string{"COMPUTE_NODE"}, + }).Extract() + th.AssertNoErr(t, err) + + cleanup := func() { DeleteResourceProvider(t, client, rp.UUID) } + return rp.UUID, cleanup +} + +func TestAllocationCandidatesList(t *testing.T) { + clients.SkipReleasesBelow(t, "stable/train") + clients.RequireAdmin(t) + + microversion := "1.34" + rpUUID, cleanup := createRPWithVCPUInventory(t, microversion) + defer cleanup() + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + client.Microversion = microversion + + page, err := allocationcandidates.List(client, allocationcandidates.ListOpts{ + Resources: "VCPU:1", + }).AllPages(context.TODO()) + th.AssertNoErr(t, err) + + result, err := allocationcandidates.ExtractAllocationCandidates(page) + th.AssertNoErr(t, err) + + th.AssertEquals(t, true, len(result.AllocationRequests) > 0) + + // Assert: The provider's summary contains the exact inventory we seeded: + // VCPU total=8, reserved=0 → capacity=8, used=0. + summary, present := result.ProviderSummaries[rpUUID] + th.AssertEquals(t, true, present) + vcpuSummary, present := summary.Resources["VCPU"] + th.AssertEquals(t, true, present) + th.AssertEquals(t, 8, vcpuSummary.Capacity) + th.AssertEquals(t, 0, vcpuSummary.Used) + th.AssertEquals(t, true, slices.Contains(*summary.Traits, "COMPUTE_NODE")) + // It is a root provider: root UUID equals its own UUID, parent is absent. + th.AssertEquals(t, rpUUID, *summary.RootProviderUUID) + th.AssertEquals(t, (*string)(nil), summary.ParentProviderUUID) + + // Assert: The allocation request contains the exact resource amount + // and the unsuffixed group maps to the newly created RP. + var req allocationcandidates.AllocationRequest + for _, r := range result.AllocationRequests { + if _, present := r.Allocations[rpUUID]; present { + req = r + break + } + } + th.AssertEquals(t, 1, req.Allocations[rpUUID].Resources["VCPU"]) + th.AssertDeepEquals(t, []string{rpUUID}, (*req.Mappings)[""]) + + tools.PrintResource(t, result) +} + +func TestAllocationCandidatesListPre129(t *testing.T) { + clients.SkipReleasesBelow(t, "stable/queens") + clients.RequireAdmin(t) + + microversion := "1.17" + rpUUID, cleanup := createRPWithVCPUInventory(t, microversion) + defer cleanup() + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + client.Microversion = microversion + + page, err := allocationcandidates.List(client, allocationcandidates.ListOpts{ + Resources: "VCPU:1", + }).AllPages(context.TODO()) + th.AssertNoErr(t, err) + + result, err := allocationcandidates.ExtractAllocationCandidates(page) + th.AssertNoErr(t, err) + + th.AssertEquals(t, true, len(result.AllocationRequests) > 0) + + summary, present := result.ProviderSummaries[rpUUID] + th.AssertEquals(t, true, present) + vcpuSummary, present := summary.Resources["VCPU"] + th.AssertEquals(t, true, present) + th.AssertEquals(t, 8, vcpuSummary.Capacity) + th.AssertEquals(t, 0, vcpuSummary.Used) + th.AssertEquals(t, true, slices.Contains(*summary.Traits, "COMPUTE_NODE")) + // Root/parent UUIDs are absent below 1.29. + th.AssertEquals(t, (*string)(nil), summary.RootProviderUUID) + th.AssertEquals(t, (*string)(nil), summary.ParentProviderUUID) + // Mappings are absent below 1.34. + th.AssertEquals(t, (*map[string][]string)(nil), result.AllocationRequests[0].Mappings) +} + +func TestAllocationCandidatesList110(t *testing.T) { + clients.SkipReleasesBelow(t, "stable/pike") + clients.RequireAdmin(t) + + microversion := "1.10" + rpUUID, cleanup := createRPWithVCPUInventory(t, microversion) + defer cleanup() + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + client.Microversion = microversion + + page, err := allocationcandidates.List(client, allocationcandidates.ListOpts{ + Resources: "VCPU:1", + }).AllPages(context.TODO()) + th.AssertNoErr(t, err) + + // Pre 1.12 uses an incompatible response format; use the separate function + // from microversions.go. + result, err := allocationcandidates.ExtractAllocationCandidates110(page) + th.AssertNoErr(t, err) + + th.AssertEquals(t, true, len(result.AllocationRequests) > 0) + th.AssertEquals(t, true, len(result.ProviderSummaries) > 0) + + // Assert: UUID of the created RP present and resource amount correct. + var foundAlloc allocationcandidates.AllocationRequest110Resource + for _, req := range result.AllocationRequests { + for _, alloc := range req.Allocations { + if alloc.ResourceProvider.UUID == rpUUID { + foundAlloc = alloc + } + } + } + th.AssertEquals(t, rpUUID, foundAlloc.ResourceProvider.UUID) + th.AssertEquals(t, 1, foundAlloc.Resources["VCPU"]) + + // Assert: The provider summary contains the expected inventory. + rpSummary, present := result.ProviderSummaries[rpUUID] + th.AssertEquals(t, true, present) + vcpuSummary, present := rpSummary.Resources["VCPU"] + th.AssertEquals(t, true, present) + th.AssertEquals(t, 8, vcpuSummary.Capacity) + th.AssertEquals(t, 0, vcpuSummary.Used) +} + +func TestAllocationCandidatesListEmpty(t *testing.T) { + clients.SkipReleasesBelow(t, "stable/pike") + clients.RequireAdmin(t) + + microversion := "1.10" + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + client.Microversion = microversion + + page, err := allocationcandidates.List(client, allocationcandidates.ListOpts{ + Resources: "MEMORY_MB:999999", + }).AllPages(context.TODO()) + th.AssertNoErr(t, err) + + result, err := allocationcandidates.ExtractAllocationCandidates(page) + th.AssertNoErr(t, err) + th.AssertEquals(t, 0, len(result.AllocationRequests)) + th.AssertEquals(t, 0, len(result.ProviderSummaries)) +} diff --git a/openstack/placement/v1/allocationcandidates/doc.go b/openstack/placement/v1/allocationcandidates/doc.go new file mode 100644 index 0000000000..ae9ceb284c --- /dev/null +++ b/openstack/placement/v1/allocationcandidates/doc.go @@ -0,0 +1,58 @@ +/* +Package allocationcandidates queries allocation candidates from the +OpenStack Placement service. + +Allocation candidates API requests are available starting from version 1.10. + +The response format changed in version 1.12: the allocations field in +allocation_requests changed from an array to a dictionary keyed by +resource provider UUID. Use the microversions.go types for 1.10-1.11. + +Example to list allocation candidates + + listOpts := allocationcandidates.ListOpts{ + Resources: "VCPU:1,MEMORY_MB:1024", + Required: []string{"HW_CPU_X86_SSE"}, + } + + page, err := allocationcandidates.List(placementClient, listOpts).AllPages(context.TODO()) + if err != nil { + panic(err) + } + allocationCandidates, err := allocationcandidates.ExtractAllocationCandidates(page) + if err != nil { + panic(err) + } + + fmt.Printf("%+v\n", allocationCandidates) + +Example to list allocation candidates with granular resource groups (microversion >= 1.33) + + listOpts := allocationcandidates.ListOpts{ + Resources: "VCPU:1,MEMORY_MB:1024", + GroupPolicy: "isolate", + ResourceGroups: map[string]allocationcandidates.ResourceGroup{ + "1": { + Resources: "SRIOV_NET_VF:1", + Required: []string{"CUSTOM_PHYSNET1"}, + }, + "_NET": { + Resources: "NET_BW_EGR_KILOBIT_PER_SEC:10", + MemberOf: "in:42896e0d-205d-4fe3-bd1e-100924931787,5e08ea53-c4c6-448e-9334-ac4953de3cfa", + }, + }, + } + + placementClient.Microversion = "1.33" + page, err := allocationcandidates.List(placementClient, listOpts).AllPages(context.TODO()) + if err != nil { + panic(err) + } + allocationCandidates, err := allocationcandidates.ExtractAllocationCandidates(page) + if err != nil { + panic(err) + } + + fmt.Printf("%+v\n", allocationCandidates) +*/ +package allocationcandidates diff --git a/openstack/placement/v1/allocationcandidates/microversions.go b/openstack/placement/v1/allocationcandidates/microversions.go new file mode 100644 index 0000000000..56b3c3c41b --- /dev/null +++ b/openstack/placement/v1/allocationcandidates/microversions.go @@ -0,0 +1,52 @@ +package allocationcandidates + +import "github.com/gophercloud/gophercloud/v2/pagination" + +// AllocationCandidates110 represents the response from a List allocation +// candidates request for microversions 1.10-1.11. +// In these versions the allocations field is an array rather than a dictionary. +type AllocationCandidates110 struct { + // AllocationRequests is a list of objects that contain information + // for creating a later allocation claim request. + AllocationRequests []AllocationRequest110 `json:"allocation_requests"` + + // ProviderSummaries is a dictionary keyed by resource provider UUID of + // inventory/capacity information for providers in the allocation_requests. + ProviderSummaries map[string]ProviderSummary110 `json:"provider_summaries"` +} + +// AllocationRequest110 represents a single allocation request for +// microversions 1.10-1.11 where allocations is an array. +type AllocationRequest110 struct { + // Allocations is a list of allocation resources per provider. + Allocations []AllocationRequest110Resource `json:"allocations"` +} + +// AllocationRequest110Resource represents a single provider allocation +// within a 1.10-1.11 allocation request. +type AllocationRequest110Resource struct { + // ResourceProvider contains the UUID of the resource provider. + ResourceProvider AllocationRequest110ResourceProvider `json:"resource_provider"` + + // Resources is a dictionary of resource class names to the amount requested. + Resources map[string]int `json:"resources"` +} + +// AllocationRequest110ResourceProvider contains the UUID of a resource provider. +type AllocationRequest110ResourceProvider struct { + UUID string `json:"uuid"` +} + +// ProviderSummary110 represents a provider summary for microversions 1.10-1.11 +// which only includes resources (no traits or parent/root UUIDs). +type ProviderSummary110 struct { + // Resources is a dictionary of resource class names to capacity/usage info. + Resources map[string]ProviderSummaryResource `json:"resources"` +} + +// ExtractAllocationCandidates110 interprets an AllocationCandidatesPage as AllocationCandidates110 (microversions 1.10-1.11). +func ExtractAllocationCandidates110(r pagination.Page) (*AllocationCandidates110, error) { + var s AllocationCandidates110 + err := (r.(AllocationCandidatesPage)).ExtractInto(&s) + return &s, err +} diff --git a/openstack/placement/v1/allocationcandidates/requests.go b/openstack/placement/v1/allocationcandidates/requests.go new file mode 100644 index 0000000000..02530a7cf2 --- /dev/null +++ b/openstack/placement/v1/allocationcandidates/requests.go @@ -0,0 +1,140 @@ +package allocationcandidates + +import ( + "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/pagination" +) + +// ListOptsBuilder allows extensions to add additional parameters to the +// List request. +type ListOptsBuilder interface { + ToAllocationCandidatesListQuery() (string, error) +} + +// ResourceGroup represents a granular resource request group. +// It is not a standalone request type, but becomes part of ListOpts, +// keyed by a user-defined suffix string. +// Available in version >= 1.25. +type ResourceGroup struct { + // Resources is a comma-separated list of resource amounts, e.g. "VCPU:1,MEMORY_MB:1024". + // Becomes the resourcesN query parameter. + Resources string + + // Required is a list of trait expressions for this group. + // Each entry becomes one requiredN query parameter. + // Available in version >= 1.39: can be repeated; supports in: syntax. + Required []string + + // MemberOf is an aggregate UUID or the prefix in: followed by a + // comma-separated list of aggregate UUIDs for this group. + // Becomes the member_ofN query parameter. + // Available in version >= 1.32: forbidden aggregates can be expressed + // with a ! prefix or the !in: prefix. + MemberOf string + + // InTree filters results to include only providers in the same tree as + // the specified provider UUID for this group. + // Becomes the in_treeN query parameter. + // Available in version >= 1.31. + InTree string +} + +// ListOpts allows filtering of allocation candidates. +type ListOpts struct { + // Resources is a comma-separated list of resource amounts that providers + // must collectively have capacity to serve, e.g. "VCPU:4,DISK_GB:64,MEMORY_MB:2048". + Resources string `q:"resources"` + + // Required is a comma-separated list of traits that a provider must have. + // Available in version >= 1.17. + // Available in version >= 1.22: prefix with ! for forbidden traits. + // Available in version >= 1.39: can be repeated and supports in: syntax. + Required []string `q:"required"` + + // MemberOf is a string representing an aggregate UUID, or the prefix in: + // followed by a comma-separated list of aggregate UUIDs. + // Available in version >= 1.21. + // Available in version >= 1.24: can be specified multiple times. + MemberOf []string `q:"member_of"` + + // InTree is a resource provider UUID. When supplied, filters candidates to + // only those providers that are in the same tree. + // Available in version >= 1.31. + InTree string `q:"in_tree"` + + // GroupPolicy indicates how the groups should interact when more than one + // resourcesN parameter is supplied. Valid values are "none" and "isolate". + // Available in version >= 1.25. + GroupPolicy string `q:"group_policy"` + + // Limit is a positive integer used to limit the maximum number of + // allocation candidates returned. + // Available in version >= 1.16. + Limit int `q:"limit"` + + // RootRequired is a comma-separated list of trait requirements that the + // root provider of the (non-sharing) tree must satisfy. + // Available in version >= 1.35. + RootRequired string `q:"root_required"` + + // SameSubtree is a comma-separated list of request group suffix strings. + // At least one of the resource providers satisfying a specified request group + // must be an ancestor of the rest. + // Available in version >= 1.36. + SameSubtree []string `q:"same_subtree"` + + // ResourceGroups allows specifying suffixed granular resource request groups. + // The map key is the non-empty group suffix (e.g. "1", "_NET1", "_STORAGE"). + // Use the top-level Resources/Required/MemberOf/InTree fields for the + // unsuffixed (default) group; do not use an empty string key here. + // In microversions 1.25-1.32 the suffix must be a numeric string. + // Starting from microversion 1.33 it can be 1-64 characters [a-zA-Z0-9_-]. + // Available in version >= 1.25. + ResourceGroups map[string]ResourceGroup `q:"-"` +} + +// ToAllocationCandidatesListQuery formats a ListOpts into a query string. +func (opts ListOpts) ToAllocationCandidatesListQuery() (string, error) { + q, err := gophercloud.BuildQueryString(opts) + if err != nil { + return "", err + } + + params := q.Query() + for suffix, group := range opts.ResourceGroups { + if group.Resources != "" { + params.Add("resources"+suffix, group.Resources) + } + for _, required := range group.Required { + if required != "" { + params.Add("required"+suffix, required) + } + } + if group.MemberOf != "" { + params.Add("member_of"+suffix, group.MemberOf) + } + if group.InTree != "" { + params.Add("in_tree"+suffix, group.InTree) + } + } + q.RawQuery = params.Encode() + + return q.String(), nil +} + +// List makes a request against the API to list allocation candidates. +func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { + url := listURL(client) + + if opts != nil { + query, err := opts.ToAllocationCandidatesListQuery() + if err != nil { + return pagination.Pager{Err: err} + } + url += query + } + + return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page { + return AllocationCandidatesPage{pagination.SinglePageBase(r)} + }) +} diff --git a/openstack/placement/v1/allocationcandidates/results.go b/openstack/placement/v1/allocationcandidates/results.go new file mode 100644 index 0000000000..44212872de --- /dev/null +++ b/openstack/placement/v1/allocationcandidates/results.go @@ -0,0 +1,85 @@ +package allocationcandidates + +import "github.com/gophercloud/gophercloud/v2/pagination" + +// AllocationCandidates represents the response from a List allocation +// candidates request for microversions 1.12 and above. +type AllocationCandidates struct { + // AllocationRequests is a list of objects that contain information + // for creating a later allocation claim request. + AllocationRequests []AllocationRequest `json:"allocation_requests"` + + // ProviderSummaries is a dictionary keyed by resource provider UUID of + // inventory/capacity information for providers in the allocation_requests. + ProviderSummaries map[string]ProviderSummary `json:"provider_summaries"` +} + +// AllocationRequest represents a single allocation request within the +// allocation candidates response. +type AllocationRequest struct { + // Allocations is a dictionary of resource allocations keyed by + // resource provider UUID. + Allocations map[string]AllocationRequestResource `json:"allocations"` + + // Mappings is a dictionary associating request group suffixes with a + // list of UUIDs identifying the resource providers that satisfied each group. + // Available in version >= 1.34. + Mappings *map[string][]string `json:"mappings"` +} + +// AllocationRequestResource represents the resources requested from a +// single resource provider within an allocation request. +type AllocationRequestResource struct { + // Resources is a dictionary of resource class names to the amount requested. + Resources map[string]int `json:"resources"` +} + +// ProviderSummary represents the summary of a resource provider's inventory +// and traits. +type ProviderSummary struct { + // Resources is a dictionary of resource class names to capacity/usage info. + Resources map[string]ProviderSummaryResource `json:"resources"` + + // Traits is a list of traits the resource provider has associated with it. + // Available in version >= 1.17. + Traits *[]string `json:"traits"` + + // ParentProviderUUID is the UUID of the immediate parent of the resource provider. + // Available in version >= 1.29. + ParentProviderUUID *string `json:"parent_provider_uuid"` + + // RootProviderUUID is the UUID of the top-most provider in this provider tree. + // Available in version >= 1.29. + RootProviderUUID *string `json:"root_provider_uuid"` +} + +// ProviderSummaryResource represents the capacity and usage of a single +// resource class for a provider. +type ProviderSummaryResource struct { + // Capacity is the amount of the resource that the provider can accommodate. + Capacity int `json:"capacity"` + + // Used is the amount of the resource that has been already allocated. + Used int `json:"used"` +} + +// AllocationCandidatesPage is the page returned from a List call. +type AllocationCandidatesPage struct { + pagination.SinglePageBase +} + +// IsEmpty determines if an AllocationCandidatesPage contains any results. +func (page AllocationCandidatesPage) IsEmpty() (bool, error) { + candidates, err := ExtractAllocationCandidates(page) + if err != nil { + return false, err + } + return len(candidates.AllocationRequests) == 0, nil +} + +// ExtractAllocationCandidates interprets an AllocationCandidatesPage as AllocationCandidates (microversion 1.12+). +func ExtractAllocationCandidates(r pagination.Page) (*AllocationCandidates, error) { + var s AllocationCandidates + err := (r.(AllocationCandidatesPage)).ExtractInto(&s) + return &s, err +} diff --git a/openstack/placement/v1/allocationcandidates/testing/doc.go b/openstack/placement/v1/allocationcandidates/testing/doc.go new file mode 100644 index 0000000000..7603f836a0 --- /dev/null +++ b/openstack/placement/v1/allocationcandidates/testing/doc.go @@ -0,0 +1 @@ +package testing diff --git a/openstack/placement/v1/allocationcandidates/testing/fixtures_test.go b/openstack/placement/v1/allocationcandidates/testing/fixtures_test.go new file mode 100644 index 0000000000..f69a1ffb62 --- /dev/null +++ b/openstack/placement/v1/allocationcandidates/testing/fixtures_test.go @@ -0,0 +1,578 @@ +package testing + +import ( + "fmt" + "net/http" + "testing" + + "github.com/gophercloud/gophercloud/v2/internal/ptr" + "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/allocationcandidates" + th "github.com/gophercloud/gophercloud/v2/testhelper" + "github.com/gophercloud/gophercloud/v2/testhelper/client" +) + +const AllocationCandidatesBody = ` +{ + "allocation_requests": [ + { + "allocations": { + "rp-uuid-1": { + "resources": { + "VCPU": 1, + "MEMORY_MB": 1024 + } + }, + "rp-uuid-2": { + "resources": { + "DISK_GB": 100 + } + } + }, + "mappings": { + "": ["rp-uuid-1"], + "_DISK": ["rp-uuid-2"] + } + } + ], + "provider_summaries": { + "rp-uuid-1": { + "resources": { + "VCPU": { + "capacity": 16, + "used": 0 + }, + "MEMORY_MB": { + "capacity": 32768, + "used": 0 + } + }, + "traits": ["HW_CPU_X86_AVX2", "HW_CPU_X86_SSE"], + "parent_provider_uuid": null, + "root_provider_uuid": "rp-uuid-1" + }, + "rp-uuid-2": { + "resources": { + "DISK_GB": { + "capacity": 1900, + "used": 0 + } + }, + "traits": ["MISC_SHARES_VIA_AGGREGATE"], + "parent_provider_uuid": null, + "root_provider_uuid": "rp-uuid-2" + } + } +} +` + +const AllocationCandidatesBodyPre134 = ` +{ + "allocation_requests": [ + { + "allocations": { + "rp-uuid-1": { + "resources": { + "VCPU": 1, + "MEMORY_MB": 1024 + } + }, + "rp-uuid-2": { + "resources": { + "DISK_GB": 100 + } + } + } + } + ], + "provider_summaries": { + "rp-uuid-1": { + "resources": { + "VCPU": { + "capacity": 16, + "used": 0 + }, + "MEMORY_MB": { + "capacity": 32768, + "used": 0 + } + }, + "traits": ["HW_CPU_X86_AVX2", "HW_CPU_X86_SSE"], + "parent_provider_uuid": null, + "root_provider_uuid": "rp-uuid-1" + }, + "rp-uuid-2": { + "resources": { + "DISK_GB": { + "capacity": 1900, + "used": 0 + } + }, + "traits": ["MISC_SHARES_VIA_AGGREGATE"], + "parent_provider_uuid": null, + "root_provider_uuid": "rp-uuid-2" + } + } +} +` + +const AllocationCandidatesBodyPre129 = ` +{ + "allocation_requests": [ + { + "allocations": { + "rp-uuid-1": { + "resources": { + "VCPU": 1, + "MEMORY_MB": 1024 + } + }, + "rp-uuid-2": { + "resources": { + "DISK_GB": 100 + } + } + } + } + ], + "provider_summaries": { + "rp-uuid-1": { + "resources": { + "VCPU": { + "capacity": 16, + "used": 0 + }, + "MEMORY_MB": { + "capacity": 32768, + "used": 0 + } + }, + "traits": ["HW_CPU_X86_AVX2", "HW_CPU_X86_SSE"] + }, + "rp-uuid-2": { + "resources": { + "DISK_GB": { + "capacity": 1900, + "used": 0 + } + }, + "traits": ["MISC_SHARES_VIA_AGGREGATE"] + } + } +} +` + +const AllocationCandidatesBodyPre117 = ` +{ + "allocation_requests": [ + { + "allocations": { + "rp-uuid-1": { + "resources": { + "VCPU": 1, + "MEMORY_MB": 1024 + } + }, + "rp-uuid-2": { + "resources": { + "DISK_GB": 100 + } + } + } + } + ], + "provider_summaries": { + "rp-uuid-1": { + "resources": { + "VCPU": { + "capacity": 16, + "used": 0 + }, + "MEMORY_MB": { + "capacity": 32768, + "used": 0 + } + } + }, + "rp-uuid-2": { + "resources": { + "DISK_GB": { + "capacity": 1900, + "used": 0 + } + } + } + } +} +` + +const AllocationCandidatesBody110 = ` +{ + "allocation_requests": [ + { + "allocations": [ + { + "resource_provider": { + "uuid": "rp-uuid-1" + }, + "resources": { + "VCPU": 1, + "MEMORY_MB": 1024 + } + } + ] + } + ], + "provider_summaries": { + "rp-uuid-1": { + "resources": { + "VCPU": { + "capacity": 16, + "used": 0 + }, + "MEMORY_MB": { + "capacity": 32768, + "used": 0 + } + } + } + } +} +` + +const AllocationCandidatesEmptyBody = ` +{ + "allocation_requests": [], + "provider_summaries": {} +} +` + +var ExpectedAllocationCandidates = allocationcandidates.AllocationCandidates{ + AllocationRequests: []allocationcandidates.AllocationRequest{ + { + Allocations: map[string]allocationcandidates.AllocationRequestResource{ + "rp-uuid-1": { + Resources: map[string]int{ + "VCPU": 1, + "MEMORY_MB": 1024, + }, + }, + "rp-uuid-2": { + Resources: map[string]int{ + "DISK_GB": 100, + }, + }, + }, + Mappings: &map[string][]string{ + "": {"rp-uuid-1"}, + "_DISK": {"rp-uuid-2"}, + }, + }, + }, + ProviderSummaries: map[string]allocationcandidates.ProviderSummary{ + "rp-uuid-1": { + Resources: map[string]allocationcandidates.ProviderSummaryResource{ + "VCPU": { + Capacity: 16, + Used: 0, + }, + "MEMORY_MB": { + Capacity: 32768, + Used: 0, + }, + }, + Traits: ptr.To([]string{"HW_CPU_X86_AVX2", "HW_CPU_X86_SSE"}), + ParentProviderUUID: nil, + RootProviderUUID: ptr.To("rp-uuid-1"), + }, + "rp-uuid-2": { + Resources: map[string]allocationcandidates.ProviderSummaryResource{ + "DISK_GB": { + Capacity: 1900, + Used: 0, + }, + }, + Traits: ptr.To([]string{"MISC_SHARES_VIA_AGGREGATE"}), + ParentProviderUUID: nil, + RootProviderUUID: ptr.To("rp-uuid-2"), + }, + }, +} + +var ExpectedAllocationCandidatesPre134 = allocationcandidates.AllocationCandidates{ + AllocationRequests: []allocationcandidates.AllocationRequest{ + { + Allocations: map[string]allocationcandidates.AllocationRequestResource{ + "rp-uuid-1": { + Resources: map[string]int{ + "VCPU": 1, + "MEMORY_MB": 1024, + }, + }, + "rp-uuid-2": { + Resources: map[string]int{ + "DISK_GB": 100, + }, + }, + }, + }, + }, + ProviderSummaries: map[string]allocationcandidates.ProviderSummary{ + "rp-uuid-1": { + Resources: map[string]allocationcandidates.ProviderSummaryResource{ + "VCPU": { + Capacity: 16, + Used: 0, + }, + "MEMORY_MB": { + Capacity: 32768, + Used: 0, + }, + }, + Traits: ptr.To([]string{"HW_CPU_X86_AVX2", "HW_CPU_X86_SSE"}), + ParentProviderUUID: nil, + RootProviderUUID: ptr.To("rp-uuid-1"), + }, + "rp-uuid-2": { + Resources: map[string]allocationcandidates.ProviderSummaryResource{ + "DISK_GB": { + Capacity: 1900, + Used: 0, + }, + }, + Traits: ptr.To([]string{"MISC_SHARES_VIA_AGGREGATE"}), + ParentProviderUUID: nil, + RootProviderUUID: ptr.To("rp-uuid-2"), + }, + }, +} + +var ExpectedAllocationCandidatesPre129 = allocationcandidates.AllocationCandidates{ + AllocationRequests: []allocationcandidates.AllocationRequest{ + { + Allocations: map[string]allocationcandidates.AllocationRequestResource{ + "rp-uuid-1": { + Resources: map[string]int{ + "VCPU": 1, + "MEMORY_MB": 1024, + }, + }, + "rp-uuid-2": { + Resources: map[string]int{ + "DISK_GB": 100, + }, + }, + }, + }, + }, + ProviderSummaries: map[string]allocationcandidates.ProviderSummary{ + "rp-uuid-1": { + Resources: map[string]allocationcandidates.ProviderSummaryResource{ + "VCPU": { + Capacity: 16, + Used: 0, + }, + "MEMORY_MB": { + Capacity: 32768, + Used: 0, + }, + }, + Traits: ptr.To([]string{"HW_CPU_X86_AVX2", "HW_CPU_X86_SSE"}), + }, + "rp-uuid-2": { + Resources: map[string]allocationcandidates.ProviderSummaryResource{ + "DISK_GB": { + Capacity: 1900, + Used: 0, + }, + }, + Traits: ptr.To([]string{"MISC_SHARES_VIA_AGGREGATE"}), + }, + }, +} + +var ExpectedAllocationCandidatesPre117 = allocationcandidates.AllocationCandidates{ + AllocationRequests: []allocationcandidates.AllocationRequest{ + { + Allocations: map[string]allocationcandidates.AllocationRequestResource{ + "rp-uuid-1": { + Resources: map[string]int{ + "VCPU": 1, + "MEMORY_MB": 1024, + }, + }, + "rp-uuid-2": { + Resources: map[string]int{ + "DISK_GB": 100, + }, + }, + }, + }, + }, + ProviderSummaries: map[string]allocationcandidates.ProviderSummary{ + "rp-uuid-1": { + Resources: map[string]allocationcandidates.ProviderSummaryResource{ + "VCPU": { + Capacity: 16, + Used: 0, + }, + "MEMORY_MB": { + Capacity: 32768, + Used: 0, + }, + }, + }, + "rp-uuid-2": { + Resources: map[string]allocationcandidates.ProviderSummaryResource{ + "DISK_GB": { + Capacity: 1900, + Used: 0, + }, + }, + }, + }, +} + +var ExpectedAllocationCandidates110 = allocationcandidates.AllocationCandidates110{ + AllocationRequests: []allocationcandidates.AllocationRequest110{ + { + Allocations: []allocationcandidates.AllocationRequest110Resource{ + { + ResourceProvider: allocationcandidates.AllocationRequest110ResourceProvider{ + UUID: "rp-uuid-1", + }, + Resources: map[string]int{ + "VCPU": 1, + "MEMORY_MB": 1024, + }, + }, + }, + }, + }, + ProviderSummaries: map[string]allocationcandidates.ProviderSummary110{ + "rp-uuid-1": { + Resources: map[string]allocationcandidates.ProviderSummaryResource{ + "VCPU": { + Capacity: 16, + Used: 0, + }, + "MEMORY_MB": { + Capacity: 32768, + Used: 0, + }, + }, + }, + }, +} + +func HandleListAllocationCandidatesSuccess(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/allocation_candidates", + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, AllocationCandidatesBody) + }) +} + +func HandleListAllocationCandidatesPre134Success(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/allocation_candidates", + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, AllocationCandidatesBodyPre134) + }) +} + +func HandleListAllocationCandidatesPre129Success(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/allocation_candidates", + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, AllocationCandidatesBodyPre129) + }) +} + +func HandleListAllocationCandidatesPre117Success(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/allocation_candidates", + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, AllocationCandidatesBodyPre117) + }) +} + +func HandleListAllocationCandidates110Success(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/allocation_candidates", + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, AllocationCandidatesBody110) + }) +} + +func HandleListAllocationCandidatesEmptySuccess(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/allocation_candidates", + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, AllocationCandidatesEmptyBody) + }) +} + +func HandleListAllocationCandidatesBadRequest(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/allocation_candidates", + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusBadRequest) + + fmt.Fprint(w, `{"errors": [{"status": 400, "detail": "Invalid resources parameter."}]}`) + }) +} + +func HandleListAllocationCandidatesWithFullQuerySuccess(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/allocation_candidates", + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + q := r.URL.Query() + th.AssertEquals(t, "VCPU:1,MEMORY_MB:1024", q.Get("resources")) + th.AssertEquals(t, "5", q.Get("limit")) + th.AssertEquals(t, "isolate", q.Get("group_policy")) + th.AssertEquals(t, "SRIOV_NET_VF:1", q.Get("resources1")) + th.AssertEquals(t, "CUSTOM_PHYSNET1", q.Get("required1")) + // required is repeated; order matches the ListOpts.Required slice order. + th.AssertDeepEquals(t, []string{"HW_CPU_X86_SSE", "!HW_CPU_X86_AVX2"}, q["required"]) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, AllocationCandidatesBody) + }) +} diff --git a/openstack/placement/v1/allocationcandidates/testing/requests_test.go b/openstack/placement/v1/allocationcandidates/testing/requests_test.go new file mode 100644 index 0000000000..14b0530512 --- /dev/null +++ b/openstack/placement/v1/allocationcandidates/testing/requests_test.go @@ -0,0 +1,140 @@ +package testing + +import ( + "context" + "net/http" + "testing" + + "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/allocationcandidates" + th "github.com/gophercloud/gophercloud/v2/testhelper" + "github.com/gophercloud/gophercloud/v2/testhelper/client" +) + +func TestListAllocationCandidatesSuccess(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleListAllocationCandidatesSuccess(t, fakeServer) + + page, err := allocationcandidates.List(client.ServiceClient(fakeServer), allocationcandidates.ListOpts{ + Resources: "VCPU:1,MEMORY_MB:1024", + }).AllPages(context.TODO()) + th.AssertNoErr(t, err) + actual, err := allocationcandidates.ExtractAllocationCandidates(page) + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedAllocationCandidates, *actual) +} + +func TestListAllocationCandidatesPre134Success(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleListAllocationCandidatesPre134Success(t, fakeServer) + + page, err := allocationcandidates.List(client.ServiceClient(fakeServer), allocationcandidates.ListOpts{ + Resources: "VCPU:1,MEMORY_MB:1024", + }).AllPages(context.TODO()) + th.AssertNoErr(t, err) + actual, err := allocationcandidates.ExtractAllocationCandidates(page) + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedAllocationCandidatesPre134, *actual) +} + +func TestListAllocationCandidatesPre129Success(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleListAllocationCandidatesPre129Success(t, fakeServer) + + page, err := allocationcandidates.List(client.ServiceClient(fakeServer), allocationcandidates.ListOpts{ + Resources: "VCPU:1,MEMORY_MB:1024", + }).AllPages(context.TODO()) + th.AssertNoErr(t, err) + actual, err := allocationcandidates.ExtractAllocationCandidates(page) + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedAllocationCandidatesPre129, *actual) +} + +func TestListAllocationCandidatesPre117Success(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleListAllocationCandidatesPre117Success(t, fakeServer) + + page, err := allocationcandidates.List(client.ServiceClient(fakeServer), allocationcandidates.ListOpts{ + Resources: "VCPU:1,MEMORY_MB:1024", + }).AllPages(context.TODO()) + th.AssertNoErr(t, err) + actual, err := allocationcandidates.ExtractAllocationCandidates(page) + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedAllocationCandidatesPre117, *actual) +} + +func TestListAllocationCandidates110Success(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleListAllocationCandidates110Success(t, fakeServer) + + page, err := allocationcandidates.List(client.ServiceClient(fakeServer), allocationcandidates.ListOpts{ + Resources: "VCPU:1,MEMORY_MB:1024", + }).AllPages(context.TODO()) + th.AssertNoErr(t, err) + actual, err := allocationcandidates.ExtractAllocationCandidates110(page) + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedAllocationCandidates110, *actual) +} + +func TestListAllocationCandidatesEmptySuccess(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleListAllocationCandidatesEmptySuccess(t, fakeServer) + + page, err := allocationcandidates.List(client.ServiceClient(fakeServer), allocationcandidates.ListOpts{ + Resources: "VCPU:1,MEMORY_MB:1024", + }).AllPages(context.TODO()) + th.AssertNoErr(t, err) + actual, err := allocationcandidates.ExtractAllocationCandidates(page) + th.AssertNoErr(t, err) + th.AssertEquals(t, 0, len(actual.AllocationRequests)) + th.AssertEquals(t, 0, len(actual.ProviderSummaries)) +} + +func TestListAllocationCandidatesBadRequest(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleListAllocationCandidatesBadRequest(t, fakeServer) + + _, err := allocationcandidates.List(client.ServiceClient(fakeServer), allocationcandidates.ListOpts{ + Resources: "INVALID", + }).AllPages(context.TODO()) + th.AssertErr(t, err) + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) +} + +func TestListAllocationCandidatesWithFullQuerySuccess(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleListAllocationCandidatesWithFullQuerySuccess(t, fakeServer) + + page, err := allocationcandidates.List(client.ServiceClient(fakeServer), allocationcandidates.ListOpts{ + Resources: "VCPU:1,MEMORY_MB:1024", + Required: []string{"HW_CPU_X86_SSE", "!HW_CPU_X86_AVX2"}, + Limit: 5, + GroupPolicy: "isolate", + ResourceGroups: map[string]allocationcandidates.ResourceGroup{ + "1": { + Resources: "SRIOV_NET_VF:1", + Required: []string{"CUSTOM_PHYSNET1"}, + }, + }, + }).AllPages(context.TODO()) + th.AssertNoErr(t, err) + actual, err := allocationcandidates.ExtractAllocationCandidates(page) + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedAllocationCandidates, *actual) +} diff --git a/openstack/placement/v1/allocationcandidates/urls.go b/openstack/placement/v1/allocationcandidates/urls.go new file mode 100644 index 0000000000..fd3f4a6743 --- /dev/null +++ b/openstack/placement/v1/allocationcandidates/urls.go @@ -0,0 +1,9 @@ +package allocationcandidates + +import "github.com/gophercloud/gophercloud/v2" + +const apiName = "allocation_candidates" + +func listURL(client *gophercloud.ServiceClient) string { + return client.ServiceURL(apiName) +} From 5492c7b025ebb2f11218c39a826b319fd9f766f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Wed, 8 Apr 2026 16:58:14 +0200 Subject: [PATCH 366/429] CI: drop pyghmi dependency It has been deprecated for a very long time [1]. [1] https://opendev.org/openstack/ironic/src/branch/master/releasenotes/notes/remove-ipminative-driver-3367d25bbcc41fdc.yaml --- .github/workflows/functional-baremetal.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/functional-baremetal.yaml b/.github/workflows/functional-baremetal.yaml index 7248cbf947..8b85e752b1 100644 --- a/.github/workflows/functional-baremetal.yaml +++ b/.github/workflows/functional-baremetal.yaml @@ -64,10 +64,8 @@ jobs: with: branch: ${{ matrix.openstack_version }} conf_overrides: | - # pyghmi is not mirrored on github - PYGHMI_REPO=https://opendev.org/x/pyghmi enable_plugin ironic https://github.com/openstack/ironic ${{ matrix.openstack_version }} - LIBS_FROM_GIT=pyghmi,virtualbmc + LIBS_FROM_GIT=virtualbmc FORCE_CONFIG_DRIVE=True Q_AGENT=openvswitch Q_ML2_TENANT_NETWORK_TYPE=vxlan From 0e864ef2debd5a5e220c44b505080b0b982a6ef9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Wed, 8 Apr 2026 17:09:34 +0200 Subject: [PATCH 367/429] CI: Get virtualbmc from pypi --- .github/workflows/functional-baremetal.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/functional-baremetal.yaml b/.github/workflows/functional-baremetal.yaml index 8b85e752b1..08ffa80ae4 100644 --- a/.github/workflows/functional-baremetal.yaml +++ b/.github/workflows/functional-baremetal.yaml @@ -65,7 +65,6 @@ jobs: branch: ${{ matrix.openstack_version }} conf_overrides: | enable_plugin ironic https://github.com/openstack/ironic ${{ matrix.openstack_version }} - LIBS_FROM_GIT=virtualbmc FORCE_CONFIG_DRIVE=True Q_AGENT=openvswitch Q_ML2_TENANT_NETWORK_TYPE=vxlan From ee950e0d6a379ed7aab8a7da94710192793dbe45 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Wed, 8 Apr 2026 17:20:26 +0100 Subject: [PATCH 368/429] script: Add script to managed required jobs You cannot do this via the workflow files and doing it via the Web API is tedious and error prone. Add a minimal script to allow us to do this via the REST API. Signed-off-by: Stephen Finucane Assisted-by: Claude Sonnet 4.6 --- script/configure-required-github-jobs | 146 ++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100755 script/configure-required-github-jobs diff --git a/script/configure-required-github-jobs b/script/configure-required-github-jobs new file mode 100755 index 0000000000..172911cd5a --- /dev/null +++ b/script/configure-required-github-jobs @@ -0,0 +1,146 @@ +#!/usr/bin/env bash +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +WORKFLOWS_DIR="${REPO_ROOT}/.github/workflows" +DRY_RUN=false + +usage() { + cat <&2; usage >&2; exit 1 ;; + esac +done + +command -v yq &>/dev/null || { echo "ERROR: yq not installed (https://github.com/mikefarah/yq)"; exit 1; } +command -v jq &>/dev/null || { echo "ERROR: jq not installed"; exit 1; } +command -v gh &>/dev/null || { echo "ERROR: gh CLI not installed"; exit 1; } +gh auth status &>/dev/null || { echo "ERROR: run 'gh auth login' first"; exit 1; } + +# Check names listed here are excluded from required status checks even if +# their workflow has an `on: merge_group` trigger. Add entries using the exact +# name format: " / " (with resolved matrix values). +SKIP_CHECKS=( + "finish" # coveralls parallel-finish job, not a test gate +) + +current_contexts=() +while IFS= read -r ctx; do + current_contexts+=("${ctx}") +done < <(gh api \ + -H "Accept: application/vnd.github+json" \ + "/repos/gophercloud/gophercloud/branches/main/protection" \ + --jq '.required_status_checks.contexts[]?' 2>/dev/null | sort) + +updated_contexts=() +for f in "${WORKFLOWS_DIR}"/*.yaml; do + # Only consider workflows that run in the merge queue + grep -q "merge_group" "${f}" || continue + + while IFS= read -r job_id; do + # Use the job's display name if set, otherwise fall back to the job ID + job_name="$(yq ".jobs[\"${job_id}\"].name // \"${job_id}\"" "${f}")" + + # Check whether this job has a matrix 'include' with a 'name' field + matrix_names="$(yq ".jobs[\"${job_id}\"].strategy.matrix.include[].name" "${f}" 2>/dev/null || true)" + + if [[ -n "${matrix_names}" ]]; then + # Expand each matrix entry, replacing ${{ matrix.name }} in the job name + while IFS= read -r matrix_val; do + resolved="${job_name//\$\{\{ matrix.name \}\}/${matrix_val}}" + updated_contexts+=("${resolved}") + done <<< "${matrix_names}" + else + updated_contexts+=("${job_name}") + fi + done < <(yq '.jobs | keys | .[]' "${f}") +done + +filtered_contexts=() +for ctx in "${updated_contexts[@]}"; do + skip=false + for skip_ctx in "${SKIP_CHECKS[@]}"; do + [[ "${ctx}" == "${skip_ctx}" ]] && { skip=true; break; } + done + "${skip}" || filtered_contexts+=("${ctx}") +done + +added_contexts=() +removed_contexts=() + +for ctx in "${filtered_contexts[@]}"; do + found=false + for cur in "${current_contexts[@]}"; do + [[ "${ctx}" == "${cur}" ]] && { found=true; break; } + done + "${found}" || added_contexts+=("${ctx}") +done + +for cur in "${current_contexts[@]}"; do + found=false + for ctx in "${filtered_contexts[@]}"; do + [[ "${cur}" == "${ctx}" ]] && { found=true; break; } + done + "${found}" || removed_contexts+=("${cur}") +done + +if [[ ${#added_contexts[@]} -eq 0 && ${#removed_contexts[@]} -eq 0 ]]; then + echo "Required status checks: no changes (${#filtered_contexts[@]} checks already configured)." +else + echo "Required status checks diff:" + for ctx in "${removed_contexts[@]}"; do printf ' - %s\n' "${ctx}"; done + for ctx in "${added_contexts[@]}"; do printf ' + %s\n' "${ctx}"; done +fi + +if "${DRY_RUN}"; then + echo "" + echo "Dry-run mode — not applying." + exit 0 +fi + +echo "" +echo "Applying to gophercloud/gophercloud:main ..." + +contexts_json="$(printf '%s\n' "${filtered_contexts[@]}" | jq -R . | jq -s .)" + +payload="$(jq -n \ + --argjson contexts "${contexts_json}" \ + '{ + required_status_checks: {strict: false, contexts: $contexts}, + enforce_admins: false, + required_pull_request_reviews: { + required_approving_review_count: 1, + dismiss_stale_reviews: true, + require_last_push_approval: true + }, + restrictions: null, + required_linear_history: true, + allow_force_pushes: false, + allow_deletions: false, + required_conversation_resolution: true + }')" + +gh api \ + --method PUT \ + -H "Accept: application/vnd.github+json" \ + "/repos/gophercloud/gophercloud/branches/main/protection" \ + --input - <<< "${payload}" + +echo "Done. Verify at: https://github.com/gophercloud/gophercloud/settings/branches" From f080482f5be59f9a222603aace70330e5ce3eec4 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 9 Apr 2026 10:08:18 +0100 Subject: [PATCH 369/429] Verify all branch protection rules Signed-off-by: Stephen Finucane --- script/configure-required-github-jobs | 55 ++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/script/configure-required-github-jobs b/script/configure-required-github-jobs index 172911cd5a..bb4412961d 100755 --- a/script/configure-required-github-jobs +++ b/script/configure-required-github-jobs @@ -9,9 +9,12 @@ usage() { cat </dev/null || { echo "ERROR: jq not installed"; exit 1; } command -v gh &>/dev/null || { echo "ERROR: gh CLI not installed"; exit 1; } gh auth status &>/dev/null || { echo "ERROR: run 'gh auth login' first"; exit 1; } +# Our non-required status check settings are defined here. These should likely +# never change. +declare -A EXPECTED_SETTINGS=( + [".enforce_admins.enabled"]="true" + [".required_linear_history.enabled"]="false" + [".allow_force_pushes.enabled"]="false" + [".allow_deletions.enabled"]="false" + [".required_conversation_resolution.enabled"]="true" + [".required_status_checks.strict"]="false" + [".required_pull_request_reviews.required_approving_review_count"]="1" + [".required_pull_request_reviews.dismiss_stale_reviews"]="true" + [".required_pull_request_reviews.require_last_push_approval"]="true" +) + # Check names listed here are excluded from required status checks even if # their workflow has an `on: merge_group` trigger. Add entries using the exact -# name format: " / " (with resolved matrix values). +# name format: "" (with resolved matrix values). SKIP_CHECKS=( "finish" # coveralls parallel-finish job, not a test gate ) +protection="$(gh api \ + -H "Accept: application/vnd.github+json" \ + "/repos/gophercloud/gophercloud/branches/main/protection")" + +settings_ok=true +for path in "${!EXPECTED_SETTINGS[@]}"; do + actual="$(jq -r "${path}" <<< "${protection}")" + expected="${EXPECTED_SETTINGS[${path}]}" + if [[ "${actual}" != "${expected}" ]]; then + echo "ERROR: branch protection drift: ${path} = ${actual} (expected ${expected})" >&2 + settings_ok=false + fi +done +if ! "${settings_ok}"; then + echo "Branch protection settings have drifted." >&2 + exit 1 +fi + +echo "Non-required status check branch protection settings are as expected." +echo + current_contexts=() while IFS= read -r ctx; do current_contexts+=("${ctx}") -done < <(gh api \ - -H "Accept: application/vnd.github+json" \ - "/repos/gophercloud/gophercloud/branches/main/protection" \ - --jq '.required_status_checks.contexts[]?' 2>/dev/null | sort) +done < <(jq -r '.required_status_checks.contexts[]?' <<< "${protection}" | sort) updated_contexts=() for f in "${WORKFLOWS_DIR}"/*.yaml; do @@ -124,14 +159,14 @@ payload="$(jq -n \ --argjson contexts "${contexts_json}" \ '{ required_status_checks: {strict: false, contexts: $contexts}, - enforce_admins: false, + enforce_admins: true, required_pull_request_reviews: { required_approving_review_count: 1, dismiss_stale_reviews: true, require_last_push_approval: true }, restrictions: null, - required_linear_history: true, + required_linear_history: false, allow_force_pushes: false, allow_deletions: false, required_conversation_resolution: true From 6bb7b9b82b8d9f15f77ae6efc8bbb9ee44dd7266 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Wed, 8 Apr 2026 12:23:41 +0100 Subject: [PATCH 370/429] ci: Drop Dalmatian testing, add Gazpacho Dalmatian goes EOL later this month [1] and Gazpacho is the latest SLURP release. Epoxy is retained as our new oldest supported release. Signed-off-by: Stephen Finucane --- .github/workflows/functional-baremetal.yaml | 6 +++--- .github/workflows/functional-basic.yaml | 6 +++--- .github/workflows/functional-blockstorage.yaml | 6 +++--- .github/workflows/functional-compute.yaml | 6 +++--- .github/workflows/functional-containerinfra.yaml | 16 ++++++++-------- .github/workflows/functional-dns.yaml | 6 +++--- .github/workflows/functional-fwaas_v2.yaml | 6 +++--- .github/workflows/functional-identity.yaml | 6 +++--- .github/workflows/functional-image.yaml | 6 +++--- .github/workflows/functional-keymanager.yaml | 10 +++++----- .github/workflows/functional-loadbalancer.yaml | 9 ++++++--- .github/workflows/functional-messaging.yaml | 6 +++--- .github/workflows/functional-networking.yaml | 6 +++--- .github/workflows/functional-objectstorage.yaml | 6 +++--- .github/workflows/functional-orchestration.yaml | 6 +++--- .github/workflows/functional-placement.yaml | 6 +++--- .../workflows/functional-sharedfilesystems.yaml | 6 +++--- .github/workflows/functional-workflow.yaml | 8 ++++---- 18 files changed, 65 insertions(+), 62 deletions(-) diff --git a/.github/workflows/functional-baremetal.yaml b/.github/workflows/functional-baremetal.yaml index b7db693b50..e7f0417392 100644 --- a/.github/workflows/functional-baremetal.yaml +++ b/.github/workflows/functional-baremetal.yaml @@ -15,12 +15,12 @@ jobs: - name: "master" openstack_version: "master" ubuntu_version: "24.04" + - name: "gazpacho" + openstack_version: "stable/2026.1" + ubuntu_version: "24.04" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" - - name: "dalmatian" - openstack_version: "stable/2024.2" - ubuntu_version: "22.04" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Ironic on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-basic.yaml b/.github/workflows/functional-basic.yaml index ee9da6e81c..ebde821546 100644 --- a/.github/workflows/functional-basic.yaml +++ b/.github/workflows/functional-basic.yaml @@ -15,12 +15,12 @@ jobs: - name: "master" openstack_version: "master" ubuntu_version: "24.04" + - name: "gazpacho" + openstack_version: "stable/2026.1" + ubuntu_version: "24.04" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" - - name: "dalmatian" - openstack_version: "stable/2024.2" - ubuntu_version: "22.04" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: basic tests on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-blockstorage.yaml b/.github/workflows/functional-blockstorage.yaml index a931d13f06..5df7932e68 100644 --- a/.github/workflows/functional-blockstorage.yaml +++ b/.github/workflows/functional-blockstorage.yaml @@ -15,12 +15,12 @@ jobs: - name: "master" openstack_version: "master" ubuntu_version: "24.04" + - name: "gazpacho" + openstack_version: "stable/2026.1" + ubuntu_version: "24.04" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" - - name: "dalmatian" - openstack_version: "stable/2024.2" - ubuntu_version: "22.04" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Cinder on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-compute.yaml b/.github/workflows/functional-compute.yaml index d280e8f328..6f0a96a964 100644 --- a/.github/workflows/functional-compute.yaml +++ b/.github/workflows/functional-compute.yaml @@ -15,12 +15,12 @@ jobs: - name: "master" openstack_version: "master" ubuntu_version: "24.04" + - name: "gazpacho" + openstack_version: "stable/2026.1" + ubuntu_version: "24.04" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" - - name: "dalmatian" - openstack_version: "stable/2024.2" - ubuntu_version: "22.04" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Nova on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-containerinfra.yaml b/.github/workflows/functional-containerinfra.yaml index db4122cc9b..a11783dfea 100644 --- a/.github/workflows/functional-containerinfra.yaml +++ b/.github/workflows/functional-containerinfra.yaml @@ -24,8 +24,8 @@ jobs: enable_plugin magnum https://github.com/openstack/magnum master MAGNUMCLIENT_BRANCH=master - - name: "epoxy" - openstack_version: "stable/2025.1" + - name: "gazpacho" + openstack_version: "stable/2026.1" ubuntu_version: "24.04" devstack_conf_overrides: | # ensure we're using a working version of setuptools @@ -34,14 +34,14 @@ jobs: sed -i 's/pip_install "-U" "pbr"/pip_install "-U" "pbr" "setuptools[core]==79.0.1"/g' \$TOP_DIR/lib/infra fi + enable_plugin magnum https://github.com/openstack/magnum stable/2026.1 + MAGNUMCLIENT_BRANCH=stable/2026.1 + - name: "epoxy" + openstack_version: "stable/2025.1" + ubuntu_version: "24.04" + devstack_conf_overrides: | enable_plugin magnum https://github.com/openstack/magnum stable/2025.1 MAGNUMCLIENT_BRANCH=stable/2025.1 - - name: "dalmatian" - openstack_version: "stable/2024.2" - ubuntu_version: "22.04" - devstack_conf_overrides: | - enable_plugin magnum https://github.com/openstack/magnum stable/2024.2 - MAGNUMCLIENT_BRANCH=stable/2024.2 runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Magnum on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-dns.yaml b/.github/workflows/functional-dns.yaml index 956b0c16da..0d32d8cc67 100644 --- a/.github/workflows/functional-dns.yaml +++ b/.github/workflows/functional-dns.yaml @@ -21,12 +21,12 @@ jobs: sed -i 's/setuptools\[core\]$/setuptools[core]==79.0.1/g' \$TOP_DIR/lib/infra \$TOP_DIR/inc/python sed -i 's/pip_install "-U" "pbr"/pip_install "-U" "pbr" "setuptools[core]==79.0.1"/g' \$TOP_DIR/lib/infra fi + - name: "gazpacho" + openstack_version: "stable/2026.1" + ubuntu_version: "24.04" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" - - name: "dalmatian" - openstack_version: "stable/2024.2" - ubuntu_version: "22.04" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Designate on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-fwaas_v2.yaml b/.github/workflows/functional-fwaas_v2.yaml index bce62f88f7..8e1d86203f 100644 --- a/.github/workflows/functional-fwaas_v2.yaml +++ b/.github/workflows/functional-fwaas_v2.yaml @@ -19,12 +19,12 @@ jobs: - name: "master" openstack_version: "master" ubuntu_version: "24.04" + - name: "gazpacho" + openstack_version: "stable/2026.1" + ubuntu_version: "24.04" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" - - name: "dalmatian" - openstack_version: "stable/2024.2" - ubuntu_version: "22.04" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: FWaaS_v2 on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-identity.yaml b/.github/workflows/functional-identity.yaml index 6f9a1d1340..a986d9df3e 100644 --- a/.github/workflows/functional-identity.yaml +++ b/.github/workflows/functional-identity.yaml @@ -15,12 +15,12 @@ jobs: - name: "master" openstack_version: "master" ubuntu_version: "24.04" + - name: "gazpacho" + openstack_version: "stable/2026.1" + ubuntu_version: "24.04" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" - - name: "dalmatian" - openstack_version: "stable/2024.2" - ubuntu_version: "22.04" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Keystone on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-image.yaml b/.github/workflows/functional-image.yaml index 980fbf7e02..4400ec1925 100644 --- a/.github/workflows/functional-image.yaml +++ b/.github/workflows/functional-image.yaml @@ -15,12 +15,12 @@ jobs: - name: "master" openstack_version: "master" ubuntu_version: "24.04" + - name: "gazpacho" + openstack_version: "stable/2026.1" + ubuntu_version: "24.04" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" - - name: "dalmatian" - openstack_version: "stable/2024.2" - ubuntu_version: "22.04" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Glance on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-keymanager.yaml b/.github/workflows/functional-keymanager.yaml index aad940ca9b..75f3e0467f 100644 --- a/.github/workflows/functional-keymanager.yaml +++ b/.github/workflows/functional-keymanager.yaml @@ -21,8 +21,8 @@ jobs: sed -i 's/setuptools\[core\]$/setuptools[core]==79.0.1/g' \$TOP_DIR/lib/infra \$TOP_DIR/inc/python sed -i 's/pip_install "-U" "pbr"/pip_install "-U" "pbr" "setuptools[core]==79.0.1"/g' \$TOP_DIR/lib/infra fi - - name: "epoxy" - openstack_version: "stable/2025.1" + - name: "gazpacho" + openstack_version: "stable/2026.1" ubuntu_version: "24.04" devstack_conf_overrides: | # ensure we're using a working version of setuptools @@ -30,9 +30,9 @@ jobs: sed -i 's/setuptools\[core\]$/setuptools[core]==79.0.1/g' \$TOP_DIR/lib/infra \$TOP_DIR/inc/python sed -i 's/pip_install "-U" "pbr"/pip_install "-U" "pbr" "setuptools[core]==79.0.1"/g' \$TOP_DIR/lib/infra fi - - name: "dalmatian" - openstack_version: "stable/2024.2" - ubuntu_version: "22.04" + - name: "epoxy" + openstack_version: "stable/2025.1" + ubuntu_version: "24.04" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Barbican on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-loadbalancer.yaml b/.github/workflows/functional-loadbalancer.yaml index e3c24ee6c9..423ae7f841 100644 --- a/.github/workflows/functional-loadbalancer.yaml +++ b/.github/workflows/functional-loadbalancer.yaml @@ -23,15 +23,18 @@ jobs: sed -i 's/setuptools\[core\]$/setuptools[core]==79.0.1/g' \$TOP_DIR/lib/infra \$TOP_DIR/inc/python sed -i 's/pip_install "-U" "pbr"/pip_install "-U" "pbr" "setuptools[core]==79.0.1"/g' \$TOP_DIR/lib/infra fi + - name: "gazpacho" + openstack_version: "stable/2026.1" + ubuntu_version: "24.04" + devstack_conf_overrides: | + LIBVIRT_CPU_MODE=host-passthrough + OCTAVIA_AMP_DISTRIBUTION_RELEASE_ID=jammy - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" devstack_conf_overrides: | LIBVIRT_CPU_MODE=host-passthrough OCTAVIA_AMP_DISTRIBUTION_RELEASE_ID=jammy - - name: "dalmatian" - openstack_version: "stable/2024.2" - ubuntu_version: "22.04" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Octavia on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-messaging.yaml b/.github/workflows/functional-messaging.yaml index c7b27e8058..143a84c466 100644 --- a/.github/workflows/functional-messaging.yaml +++ b/.github/workflows/functional-messaging.yaml @@ -15,12 +15,12 @@ jobs: - name: "master" openstack_version: "master" ubuntu_version: "24.04" + - name: "gazpacho" + openstack_version: "stable/2026.1" + ubuntu_version: "24.04" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" - - name: "dalmatian" - openstack_version: "stable/2024.2" - ubuntu_version: "22.04" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Zaqar on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-networking.yaml b/.github/workflows/functional-networking.yaml index eab70110b7..b68e0f8788 100644 --- a/.github/workflows/functional-networking.yaml +++ b/.github/workflows/functional-networking.yaml @@ -15,12 +15,12 @@ jobs: - name: "master" openstack_version: "master" ubuntu_version: "24.04" + - name: "gazpacho" + openstack_version: "stable/2026.1" + ubuntu_version: "24.04" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" - - name: "dalmatian" - openstack_version: "stable/2024.2" - ubuntu_version: "22.04" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Neutron on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-objectstorage.yaml b/.github/workflows/functional-objectstorage.yaml index 07c29a7438..14a574cdba 100644 --- a/.github/workflows/functional-objectstorage.yaml +++ b/.github/workflows/functional-objectstorage.yaml @@ -15,12 +15,12 @@ jobs: - name: "master" openstack_version: "master" ubuntu_version: "24.04" + - name: "gazpacho" + openstack_version: "stable/2026.1" + ubuntu_version: "24.04" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" - - name: "dalmatian" - openstack_version: "stable/2024.2" - ubuntu_version: "22.04" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Swift on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-orchestration.yaml b/.github/workflows/functional-orchestration.yaml index 8396b954fb..72e7791674 100644 --- a/.github/workflows/functional-orchestration.yaml +++ b/.github/workflows/functional-orchestration.yaml @@ -15,12 +15,12 @@ jobs: - name: "master" openstack_version: "master" ubuntu_version: "24.04" + - name: "gazpacho" + openstack_version: "stable/2026.1" + ubuntu_version: "24.04" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" - - name: "dalmatian" - openstack_version: "stable/2024.2" - ubuntu_version: "22.04" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Heat on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-placement.yaml b/.github/workflows/functional-placement.yaml index 99fa2615c7..ef8fb9e3da 100644 --- a/.github/workflows/functional-placement.yaml +++ b/.github/workflows/functional-placement.yaml @@ -15,12 +15,12 @@ jobs: - name: "master" openstack_version: "master" ubuntu_version: "24.04" + - name: "gazpacho" + openstack_version: "stable/2026.1" + ubuntu_version: "24.04" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" - - name: "dalmatian" - openstack_version: "stable/2024.2" - ubuntu_version: "22.04" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Placement on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-sharedfilesystems.yaml b/.github/workflows/functional-sharedfilesystems.yaml index 928f297b24..289e884d30 100644 --- a/.github/workflows/functional-sharedfilesystems.yaml +++ b/.github/workflows/functional-sharedfilesystems.yaml @@ -21,12 +21,12 @@ jobs: sed -i 's/setuptools\[core\]$/setuptools[core]==79.0.1/g' \$TOP_DIR/lib/infra \$TOP_DIR/inc/python sed -i 's/pip_install "-U" "pbr"/pip_install "-U" "pbr" "setuptools[core]==79.0.1"/g' \$TOP_DIR/lib/infra fi + - name: "gazpacho" + openstack_version: "stable/2026.1" + ubuntu_version: "24.04" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" - - name: "dalmatian" - openstack_version: "stable/2024.2" - ubuntu_version: "22.04" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Manila on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-workflow.yaml b/.github/workflows/functional-workflow.yaml index 77ec801634..faa216b566 100644 --- a/.github/workflows/functional-workflow.yaml +++ b/.github/workflows/functional-workflow.yaml @@ -16,14 +16,14 @@ jobs: openstack_version: "master" ubuntu_version: "24.04" mistral_plugin_version: "master" + - name: "gazpacho" + openstack_version: "stable/2026.1" + ubuntu_version: "24.04" + mistral_plugin_version: "stable/2026.1" - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" mistral_plugin_version: "stable/2025.1" - - name: "dalmatian" - openstack_version: "stable/2024.2" - ubuntu_version: "22.04" - mistral_plugin_version: "stable/2024.2" runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Mistral on Deploy OpenStack ${{ matrix.name }} steps: From 8fdecf282260738f25a4be3853e797bbb064efaf Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Wed, 8 Apr 2026 12:25:32 +0100 Subject: [PATCH 371/429] ci: Remove setuptools overrides Most of these issues have been fixed upstream by now. Signed-off-by: Stephen Finucane --- .github/workflows/functional-containerinfra.yaml | 12 ------------ .github/workflows/functional-dns.yaml | 6 ------ .github/workflows/functional-keymanager.yaml | 12 ------------ .github/workflows/functional-loadbalancer.yaml | 5 ----- .github/workflows/functional-metric.yaml | 6 ------ .github/workflows/functional-sharedfilesystems.yaml | 6 ------ 6 files changed, 47 deletions(-) diff --git a/.github/workflows/functional-containerinfra.yaml b/.github/workflows/functional-containerinfra.yaml index a11783dfea..eb0d408214 100644 --- a/.github/workflows/functional-containerinfra.yaml +++ b/.github/workflows/functional-containerinfra.yaml @@ -16,24 +16,12 @@ jobs: openstack_version: "master" ubuntu_version: "24.04" devstack_conf_overrides: | - # ensure we're using a working version of setuptools - if [ -n "\$TOP_DIR" ]; then - sed -i 's/setuptools\[core\]$/setuptools[core]==79.0.1/g' \$TOP_DIR/lib/infra \$TOP_DIR/inc/python - sed -i 's/pip_install "-U" "pbr"/pip_install "-U" "pbr" "setuptools[core]==79.0.1"/g' \$TOP_DIR/lib/infra - fi - enable_plugin magnum https://github.com/openstack/magnum master MAGNUMCLIENT_BRANCH=master - name: "gazpacho" openstack_version: "stable/2026.1" ubuntu_version: "24.04" devstack_conf_overrides: | - # ensure we're using a working version of setuptools - if [ -n "\$TOP_DIR" ]; then - sed -i 's/setuptools\[core\]$/setuptools[core]==79.0.1/g' \$TOP_DIR/lib/infra \$TOP_DIR/inc/python - sed -i 's/pip_install "-U" "pbr"/pip_install "-U" "pbr" "setuptools[core]==79.0.1"/g' \$TOP_DIR/lib/infra - fi - enable_plugin magnum https://github.com/openstack/magnum stable/2026.1 MAGNUMCLIENT_BRANCH=stable/2026.1 - name: "epoxy" diff --git a/.github/workflows/functional-dns.yaml b/.github/workflows/functional-dns.yaml index 0d32d8cc67..1ab0e95f4f 100644 --- a/.github/workflows/functional-dns.yaml +++ b/.github/workflows/functional-dns.yaml @@ -15,12 +15,6 @@ jobs: - name: "master" openstack_version: "master" ubuntu_version: "24.04" - devstack_conf_overrides: | - # ensure we're using a working version of setuptools - if [ -n "\$TOP_DIR" ]; then - sed -i 's/setuptools\[core\]$/setuptools[core]==79.0.1/g' \$TOP_DIR/lib/infra \$TOP_DIR/inc/python - sed -i 's/pip_install "-U" "pbr"/pip_install "-U" "pbr" "setuptools[core]==79.0.1"/g' \$TOP_DIR/lib/infra - fi - name: "gazpacho" openstack_version: "stable/2026.1" ubuntu_version: "24.04" diff --git a/.github/workflows/functional-keymanager.yaml b/.github/workflows/functional-keymanager.yaml index 75f3e0467f..7bb4cdc1d9 100644 --- a/.github/workflows/functional-keymanager.yaml +++ b/.github/workflows/functional-keymanager.yaml @@ -15,21 +15,9 @@ jobs: - name: "master" openstack_version: "master" ubuntu_version: "24.04" - devstack_conf_overrides: | - # ensure we're using a working version of setuptools - if [ -n "\$TOP_DIR" ]; then - sed -i 's/setuptools\[core\]$/setuptools[core]==79.0.1/g' \$TOP_DIR/lib/infra \$TOP_DIR/inc/python - sed -i 's/pip_install "-U" "pbr"/pip_install "-U" "pbr" "setuptools[core]==79.0.1"/g' \$TOP_DIR/lib/infra - fi - name: "gazpacho" openstack_version: "stable/2026.1" ubuntu_version: "24.04" - devstack_conf_overrides: | - # ensure we're using a working version of setuptools - if [ -n "\$TOP_DIR" ]; then - sed -i 's/setuptools\[core\]$/setuptools[core]==79.0.1/g' \$TOP_DIR/lib/infra \$TOP_DIR/inc/python - sed -i 's/pip_install "-U" "pbr"/pip_install "-U" "pbr" "setuptools[core]==79.0.1"/g' \$TOP_DIR/lib/infra - fi - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" diff --git a/.github/workflows/functional-loadbalancer.yaml b/.github/workflows/functional-loadbalancer.yaml index 423ae7f841..588bc400f8 100644 --- a/.github/workflows/functional-loadbalancer.yaml +++ b/.github/workflows/functional-loadbalancer.yaml @@ -18,11 +18,6 @@ jobs: devstack_conf_overrides: | LIBVIRT_CPU_MODE=host-passthrough OCTAVIA_AMP_DISTRIBUTION_RELEASE_ID=jammy - # ensure we're using a working version of setuptools - if [ -n "\$TOP_DIR" ]; then - sed -i 's/setuptools\[core\]$/setuptools[core]==79.0.1/g' \$TOP_DIR/lib/infra \$TOP_DIR/inc/python - sed -i 's/pip_install "-U" "pbr"/pip_install "-U" "pbr" "setuptools[core]==79.0.1"/g' \$TOP_DIR/lib/infra - fi - name: "gazpacho" openstack_version: "stable/2026.1" ubuntu_version: "24.04" diff --git a/.github/workflows/functional-metric.yaml b/.github/workflows/functional-metric.yaml index 8efa8d14e9..b00719e921 100644 --- a/.github/workflows/functional-metric.yaml +++ b/.github/workflows/functional-metric.yaml @@ -15,12 +15,6 @@ jobs: - name: "master" openstack_version: "master" ubuntu_version: "24.04" - devstack_conf_overrides: | - # ensure we're using a working version of setuptools - if [ -n "\$TOP_DIR" ]; then - sed -i 's/setuptools\[core\]$/setuptools[core]==79.0.1/g' \$TOP_DIR/lib/infra \$TOP_DIR/inc/python - sed -i 's/pip_install "-U" "pbr"/pip_install "-U" "pbr" "setuptools[core]==79.0.1"/g' \$TOP_DIR/lib/infra - fi runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Aetos on OpenStack ${{ matrix.name }} steps: diff --git a/.github/workflows/functional-sharedfilesystems.yaml b/.github/workflows/functional-sharedfilesystems.yaml index 289e884d30..fd1fa1ec22 100644 --- a/.github/workflows/functional-sharedfilesystems.yaml +++ b/.github/workflows/functional-sharedfilesystems.yaml @@ -15,12 +15,6 @@ jobs: - name: "master" openstack_version: "master" ubuntu_version: "24.04" - devstack_conf_overrides: | - # ensure we're using a working version of setuptools - if [ -n "\$TOP_DIR" ]; then - sed -i 's/setuptools\[core\]$/setuptools[core]==79.0.1/g' \$TOP_DIR/lib/infra \$TOP_DIR/inc/python - sed -i 's/pip_install "-U" "pbr"/pip_install "-U" "pbr" "setuptools[core]==79.0.1"/g' \$TOP_DIR/lib/infra - fi - name: "gazpacho" openstack_version: "stable/2026.1" ubuntu_version: "24.04" From de92433b5d19b20cf28fe5cd45480e9abd433764 Mon Sep 17 00:00:00 2001 From: Dominik Danelski Date: Thu, 9 Apr 2026 22:45:33 +0200 Subject: [PATCH 372/429] Properly handle pre-1.19 in resourceproviders aggregates We don't provide resource provider's generation in request nor do we get it back in response. The original tests got it slightly wrong; fix it. Automatically correct the request if user wrongly provides generation in opts for pre-1.19. Signed-off-by: Dominik Danelski --- .../placement/v1/resourceproviders_test.go | 69 +++++++++++++++++++ .../placement/v1/resourceproviders/doc.go | 7 +- .../v1/resourceproviders/requests.go | 6 +- .../testing/fixtures_test.go | 12 +++- .../testing/requests_test.go | 40 +++++++++-- .../placement/v1/resourceproviders/util.go | 14 ++++ 6 files changed, 138 insertions(+), 10 deletions(-) create mode 100644 openstack/placement/v1/resourceproviders/util.go diff --git a/internal/acceptance/openstack/placement/v1/resourceproviders_test.go b/internal/acceptance/openstack/placement/v1/resourceproviders_test.go index c60f0b93a4..277dd5d38b 100644 --- a/internal/acceptance/openstack/placement/v1/resourceproviders_test.go +++ b/internal/acceptance/openstack/placement/v1/resourceproviders_test.go @@ -587,3 +587,72 @@ func TestResourceProviderAggregatesUpdateNegative(t *testing.T) { _, err = resourceproviders.UpdateAggregates(context.TODO(), client, resourceProvider.UUID, updateOpts).Extract() th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusConflict)) } + +func TestResourceProviderAggregatesUpdatePreGenerationSuccess(t *testing.T) { + // Before microversion 1.19, the PUT request body is just a list of aggregate UUIDs. + clients.SkipReleasesBelow(t, "stable/ocata") + clients.RequireAdmin(t) + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + resourceProvider, err := CreateResourceProvider(t, client) + th.AssertNoErr(t, err) + defer DeleteResourceProvider(t, client, resourceProvider.UUID) + + client.Microversion = "1.1" + + updateOpts := resourceproviders.UpdateAggregatesOpts{ + Aggregates: []string{ + "6d84f6f6-7736-40ff-84d2-7db47f18ea25", + "f11f14bc-6f17-4f0a-b7c2-44b3e685ccf4", + }, + } + + _, err = resourceproviders.UpdateAggregates(context.TODO(), client, resourceProvider.UUID, updateOpts).Extract() + th.AssertNoErr(t, err) + + after, err := resourceproviders.GetAggregates(context.TODO(), client, resourceProvider.UUID).Extract() + th.AssertNoErr(t, err) + th.AssertEquals(t, len(updateOpts.Aggregates), len(after.Aggregates)) + + for _, aggregate := range updateOpts.Aggregates { + th.AssertEquals(t, true, slices.Contains(after.Aggregates, aggregate)) + } +} + +func TestResourceProviderAggregatesUpdatePreGenerationWithGenerationSuccess(t *testing.T) { + // Before microversion 1.19, ResourceProviderGeneration in opts is silently stripped from + // the request body, so the operation must succeed even when the caller supplies it. + clients.SkipReleasesBelow(t, "stable/ocata") + clients.RequireAdmin(t) + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + resourceProvider, err := CreateResourceProvider(t, client) + th.AssertNoErr(t, err) + defer DeleteResourceProvider(t, client, resourceProvider.UUID) + + client.Microversion = "1.1" + + gen := 1 + updateOpts := resourceproviders.UpdateAggregatesOpts{ + ResourceProviderGeneration: &gen, + Aggregates: []string{ + "6d84f6f6-7736-40ff-84d2-7db47f18ea25", + "f11f14bc-6f17-4f0a-b7c2-44b3e685ccf4", + }, + } + + _, err = resourceproviders.UpdateAggregates(context.TODO(), client, resourceProvider.UUID, updateOpts).Extract() + th.AssertNoErr(t, err) + + after, err := resourceproviders.GetAggregates(context.TODO(), client, resourceProvider.UUID).Extract() + th.AssertNoErr(t, err) + th.AssertEquals(t, len(updateOpts.Aggregates), len(after.Aggregates)) + + for _, aggregate := range updateOpts.Aggregates { + th.AssertEquals(t, true, slices.Contains(after.Aggregates, aggregate)) + } +} diff --git a/openstack/placement/v1/resourceproviders/doc.go b/openstack/placement/v1/resourceproviders/doc.go index 10e65ea7f5..d0a6caa515 100644 --- a/openstack/placement/v1/resourceproviders/doc.go +++ b/openstack/placement/v1/resourceproviders/doc.go @@ -172,9 +172,12 @@ Example to get resource providers aggregates panic(err) } -Example to update resource providers aggregates +# Example to update resource providers aggregates - placementClient.Microversion = "1.1" +For microversion 1.18 and earlier the ResourceProviderGeneration is optional and would be ignored if provided, +as it was not supported pre-1.19. For greater safety, it is recommended to use the newer microversion. + + placementClient.Microversion = "1.19" updateOpts := resourceproviders.UpdateAggregatesOpts{ ResourceProviderGeneration: rp.ResourceProviderGeneration, diff --git a/openstack/placement/v1/resourceproviders/requests.go b/openstack/placement/v1/resourceproviders/requests.go index 1f7eed4af6..f71bfe8519 100644 --- a/openstack/placement/v1/resourceproviders/requests.go +++ b/openstack/placement/v1/resourceproviders/requests.go @@ -285,7 +285,11 @@ func UpdateAggregates(ctx context.Context, client *gophercloud.ServiceClient, re return } - resp, err := client.Put(ctx, updateResourceProviderAggregatesURL(client, resourceProviderID), b, &r.Body, &gophercloud.RequestOpts{ + var body any = b + if useGenerations := microversionAtLeast(client, 1, 19); !useGenerations { + body = b["aggregates"] + } + resp, err := client.Put(ctx, updateResourceProviderAggregatesURL(client, resourceProviderID), body, &r.Body, &gophercloud.RequestOpts{ OkCodes: []int{200}, }) _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) diff --git a/openstack/placement/v1/resourceproviders/testing/fixtures_test.go b/openstack/placement/v1/resourceproviders/testing/fixtures_test.go index 8b25cd8102..45faff6427 100644 --- a/openstack/placement/v1/resourceproviders/testing/fixtures_test.go +++ b/openstack/placement/v1/resourceproviders/testing/fixtures_test.go @@ -252,7 +252,13 @@ const AggregatesUpdateBody = ` } ` -const AggregatesUpdateBodyPreGeneration = ` +// AggregatesUpdateRequestPreGeneration is the raw JSON array sent as the PUT request body +// for microversions < 1.19, where the payload is just a list of aggregate UUIDs. +const AggregatesUpdateRequestPreGeneration = `["89f68995-4fd8-4f8b-a03e-7d5980762ff2","16d0e5f2-7f66-4f32-9040-b09de2f40afd"]` + +// AggregatesUpdateBodyWithoutGeneration is the pre-1.19 server response body for an aggregates update. +// Unlike the request, the response is not flat. +const AggregatesUpdateBodyWithoutGeneration = ` { "aggregates": [ "89f68995-4fd8-4f8b-a03e-7d5980762ff2", @@ -793,9 +799,9 @@ func HandleResourceProviderUpdateAndGetAggregatesPreGenerationSuccess(t *testing th.TestHeader(t, r, "X-Auth-Token", client.TokenID) th.TestHeader(t, r, "Content-Type", "application/json") th.TestHeader(t, r, "Accept", "application/json") - th.TestJSONRequest(t, r, AggregatesUpdateBodyPreGeneration) + th.TestJSONRequest(t, r, AggregatesUpdateRequestPreGeneration) - body = AggregatesUpdateBodyPreGeneration + body = AggregatesUpdateBodyWithoutGeneration w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) diff --git a/openstack/placement/v1/resourceproviders/testing/requests_test.go b/openstack/placement/v1/resourceproviders/testing/requests_test.go index ccdef63c6a..36909fb3df 100644 --- a/openstack/placement/v1/resourceproviders/testing/requests_test.go +++ b/openstack/placement/v1/resourceproviders/testing/requests_test.go @@ -315,11 +315,14 @@ func TestUpdateResourceProviderAggregatesSuccess(t *testing.T) { HandleResourceProviderUpdateAndGetAggregatesSuccess(t, fakeServer) + sc := client.ServiceClient(fakeServer) + sc.Microversion = "1.19" + updateOpts := resourceproviders.UpdateAggregatesOpts(ExpectedUpdatedAggregates) - _, err := resourceproviders.UpdateAggregates(context.TODO(), client.ServiceClient(fakeServer), ResourceProviderTestID, updateOpts).Extract() + _, err := resourceproviders.UpdateAggregates(context.TODO(), sc, ResourceProviderTestID, updateOpts).Extract() th.AssertNoErr(t, err) - actual, err := resourceproviders.GetAggregates(context.TODO(), client.ServiceClient(fakeServer), ResourceProviderTestID).Extract() + actual, err := resourceproviders.GetAggregates(context.TODO(), sc, ResourceProviderTestID).Extract() th.AssertNoErr(t, err) th.AssertDeepEquals(t, ExpectedUpdatedAggregates, *actual) } @@ -330,13 +333,42 @@ func TestUpdateResourceProviderAggregatesPreGenerationSuccess(t *testing.T) { HandleResourceProviderUpdateAndGetAggregatesPreGenerationSuccess(t, fakeServer) + sc := client.ServiceClient(fakeServer) + sc.Microversion = "1.10" + updateOpts := resourceproviders.UpdateAggregatesOpts{ Aggregates: ExpectedUpdatedAggregatesPreGeneration.Aggregates, } - _, err := resourceproviders.UpdateAggregates(context.TODO(), client.ServiceClient(fakeServer), ResourceProviderTestID, updateOpts).Extract() + _, err := resourceproviders.UpdateAggregates(context.TODO(), sc, ResourceProviderTestID, updateOpts).Extract() th.AssertNoErr(t, err) - actual, err := resourceproviders.GetAggregates(context.TODO(), client.ServiceClient(fakeServer), ResourceProviderTestID).Extract() + actual, err := resourceproviders.GetAggregates(context.TODO(), sc, ResourceProviderTestID).Extract() + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedUpdatedAggregatesPreGeneration, *actual) +} + +// TestUpdateResourceProviderAggregatesPreGenerationWithGenerationInOptsSuccess validates that +// when the microversion is < 1.19 but the caller supplies ResourceProviderGeneration in opts, +// the generation field is stripped from the request body and the operation succeeds. +func TestUpdateResourceProviderAggregatesPreGenerationWithGenerationInOptsSuccess(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + // Reuse the same handler: it validates the request body contains only aggregates (no generation). + HandleResourceProviderUpdateAndGetAggregatesPreGenerationSuccess(t, fakeServer) + + sc := client.ServiceClient(fakeServer) + sc.Microversion = "1.10" + + gen := 1 + updateOpts := resourceproviders.UpdateAggregatesOpts{ + ResourceProviderGeneration: &gen, + Aggregates: ExpectedUpdatedAggregatesPreGeneration.Aggregates, + } + _, err := resourceproviders.UpdateAggregates(context.TODO(), sc, ResourceProviderTestID, updateOpts).Extract() + th.AssertNoErr(t, err) + + actual, err := resourceproviders.GetAggregates(context.TODO(), sc, ResourceProviderTestID).Extract() th.AssertNoErr(t, err) th.AssertDeepEquals(t, ExpectedUpdatedAggregatesPreGeneration, *actual) } diff --git a/openstack/placement/v1/resourceproviders/util.go b/openstack/placement/v1/resourceproviders/util.go new file mode 100644 index 0000000000..ecddaed8ea --- /dev/null +++ b/openstack/placement/v1/resourceproviders/util.go @@ -0,0 +1,14 @@ +package resourceproviders + +import ( + "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/openstack/utils" +) + +func microversionAtLeast(client *gophercloud.ServiceClient, major, minor int) bool { + M, m, err := utils.ParseMicroversion(client.Microversion) + if err != nil { + return false + } + return M > major || (M == major && m >= minor) +} From 0f346066c8b772165b73bb7ee4f3862608262402 Mon Sep 17 00:00:00 2001 From: Dominik Danelski Date: Fri, 10 Apr 2026 00:54:39 +0200 Subject: [PATCH 373/429] Fix IsEmpty for allocation_candidates in 1.10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Full deserialisation could crash on older structure defined for 1.10. Co-authored-by: Martin André Signed-off-by: Dominik Danelski --- .../placement/v1/allocationcandidates_test.go | 26 +++++++++++++++++++ .../v1/allocationcandidates/results.go | 14 +++++++--- .../testing/requests_test.go | 20 ++++++++++++++ 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/internal/acceptance/openstack/placement/v1/allocationcandidates_test.go b/internal/acceptance/openstack/placement/v1/allocationcandidates_test.go index 2cfc4074ac..38cc6dcc06 100644 --- a/internal/acceptance/openstack/placement/v1/allocationcandidates_test.go +++ b/internal/acceptance/openstack/placement/v1/allocationcandidates_test.go @@ -187,6 +187,28 @@ func TestAllocationCandidatesList110(t *testing.T) { th.AssertEquals(t, 0, vcpuSummary.Used) } +func TestAllocationCandidatesIsEmpty110(t *testing.T) { + clients.SkipReleasesBelow(t, "stable/pike") + clients.RequireAdmin(t) + + microversion := "1.10" + _, cleanup := createRPWithVCPUInventory(t, microversion) + defer cleanup() + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + client.Microversion = microversion + + page, err := allocationcandidates.List(client, allocationcandidates.ListOpts{ + Resources: "VCPU:1", + }).AllPages(context.TODO()) + th.AssertNoErr(t, err) + + isEmpty, err := page.IsEmpty() + th.AssertNoErr(t, err) + th.AssertEquals(t, false, isEmpty) +} + func TestAllocationCandidatesListEmpty(t *testing.T) { clients.SkipReleasesBelow(t, "stable/pike") clients.RequireAdmin(t) @@ -205,4 +227,8 @@ func TestAllocationCandidatesListEmpty(t *testing.T) { th.AssertNoErr(t, err) th.AssertEquals(t, 0, len(result.AllocationRequests)) th.AssertEquals(t, 0, len(result.ProviderSummaries)) + + isEmpty, err := page.IsEmpty() + th.AssertNoErr(t, err) + th.AssertEquals(t, true, isEmpty) } diff --git a/openstack/placement/v1/allocationcandidates/results.go b/openstack/placement/v1/allocationcandidates/results.go index 44212872de..8b94a0a7f5 100644 --- a/openstack/placement/v1/allocationcandidates/results.go +++ b/openstack/placement/v1/allocationcandidates/results.go @@ -1,6 +1,10 @@ package allocationcandidates -import "github.com/gophercloud/gophercloud/v2/pagination" +import ( + "encoding/json" + + "github.com/gophercloud/gophercloud/v2/pagination" +) // AllocationCandidates represents the response from a List allocation // candidates request for microversions 1.12 and above. @@ -69,12 +73,16 @@ type AllocationCandidatesPage struct { } // IsEmpty determines if an AllocationCandidatesPage contains any results. +// It avoids full deserialization so that it works across all microversions, func (page AllocationCandidatesPage) IsEmpty() (bool, error) { - candidates, err := ExtractAllocationCandidates(page) + var s struct { + AllocationRequests []json.RawMessage `json:"allocation_requests"` + } + err := page.ExtractInto(&s) if err != nil { return false, err } - return len(candidates.AllocationRequests) == 0, nil + return len(s.AllocationRequests) == 0, nil } // ExtractAllocationCandidates interprets an AllocationCandidatesPage as AllocationCandidates (microversion 1.12+). diff --git a/openstack/placement/v1/allocationcandidates/testing/requests_test.go b/openstack/placement/v1/allocationcandidates/testing/requests_test.go index 14b0530512..98bb29b9c9 100644 --- a/openstack/placement/v1/allocationcandidates/testing/requests_test.go +++ b/openstack/placement/v1/allocationcandidates/testing/requests_test.go @@ -100,6 +100,26 @@ func TestListAllocationCandidatesEmptySuccess(t *testing.T) { th.AssertNoErr(t, err) th.AssertEquals(t, 0, len(actual.AllocationRequests)) th.AssertEquals(t, 0, len(actual.ProviderSummaries)) + + isEmpty, err := page.IsEmpty() + th.AssertNoErr(t, err) + th.AssertEquals(t, true, isEmpty) +} + +func TestIsEmpty110Success(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleListAllocationCandidates110Success(t, fakeServer) + + page, err := allocationcandidates.List(client.ServiceClient(fakeServer), allocationcandidates.ListOpts{ + Resources: "VCPU:1,MEMORY_MB:1024", + }).AllPages(context.TODO()) + th.AssertNoErr(t, err) + + isEmpty, err := page.IsEmpty() + th.AssertNoErr(t, err) + th.AssertEquals(t, false, isEmpty) } func TestListAllocationCandidatesBadRequest(t *testing.T) { From 88702e7f4d002fc44809f45d2cb0d3480616da5b Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Fri, 10 Apr 2026 13:37:01 +0100 Subject: [PATCH 374/429] Address review comments from resourceprovider aggregates PR Per comments [1], remove an unnecessary helper and tweak some tests. [1] https://github.com/gophercloud/gophercloud/pull/3709 Signed-off-by: Stephen Finucane --- .../placement/v1/resourceproviders_test.go | 48 ++++--------------- .../v1/resourceproviders/requests.go | 13 ++++- .../placement/v1/resourceproviders/util.go | 14 ------ 3 files changed, 21 insertions(+), 54 deletions(-) delete mode 100644 openstack/placement/v1/resourceproviders/util.go diff --git a/internal/acceptance/openstack/placement/v1/resourceproviders_test.go b/internal/acceptance/openstack/placement/v1/resourceproviders_test.go index 277dd5d38b..3babbf9006 100644 --- a/internal/acceptance/openstack/placement/v1/resourceproviders_test.go +++ b/internal/acceptance/openstack/placement/v1/resourceproviders_test.go @@ -453,47 +453,33 @@ func TestResourceProviderAllocations(t *testing.T) { tools.PrintResource(t, usage) } -func TestResourceProviderAggregatesGetSuccess(t *testing.T) { - // Resource_provider_generation in the aggregates response was introduced in microversion 1.19. +func TestResourceProviderAggregates(t *testing.T) { clients.SkipReleasesBelow(t, "stable/ocata") clients.RequireAdmin(t) client, err := clients.NewPlacementV1Client() th.AssertNoErr(t, err) + // first create new resource provider resourceProvider, err := CreateResourceProvider(t, client) th.AssertNoErr(t, err) defer DeleteResourceProvider(t, client, resourceProvider.UUID) + // now get the aggregates for same client.Microversion = "1.19" - aggregates, err := resourceproviders.GetAggregates(context.TODO(), client, resourceProvider.UUID).Extract() th.AssertNoErr(t, err) th.AssertEquals(t, true, aggregates.ResourceProviderGeneration != nil) -} - -func TestResourceProviderAggregatesGetPreGenerationSuccess(t *testing.T) { - // Resource provider aggregates operations were introduced in microversion 1.1. - clients.SkipReleasesBelow(t, "stable/ocata") - clients.RequireAdmin(t) - - client, err := clients.NewPlacementV1Client() - th.AssertNoErr(t, err) - - resourceProvider, err := CreateResourceProvider(t, client) - th.AssertNoErr(t, err) - defer DeleteResourceProvider(t, client, resourceProvider.UUID) + // ensure that we handle older microversions where generation is missing client.Microversion = "1.1" - - aggregates, err := resourceproviders.GetAggregates(context.TODO(), client, resourceProvider.UUID).Extract() + aggregates, err = resourceproviders.GetAggregates(context.TODO(), client, resourceProvider.UUID).Extract() th.AssertNoErr(t, err) th.AssertEquals(t, 0, len(aggregates.Aggregates)) th.AssertDeepEquals(t, (*int)(nil), aggregates.ResourceProviderGeneration) } -func TestResourceProviderAggregatesGetNegative(t *testing.T) { - // Resource_provider_generation in the aggregates response was introduced in microversion 1.19. +func TestResourceProviderAggregatesNotFound(t *testing.T) { clients.SkipReleasesBelow(t, "stable/ocata") clients.RequireAdmin(t) @@ -501,27 +487,15 @@ func TestResourceProviderAggregatesGetNegative(t *testing.T) { th.AssertNoErr(t, err) client.Microversion = "1.19" - _, err = resourceproviders.GetAggregates(context.TODO(), client, "00000000-0000-0000-0000-000000000000").Extract() th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) -} - -func TestResourceProviderAggregatesGetPreGenerationNegative(t *testing.T) { - // Resource provider aggregates operations were introduced in microversion 1.1. - clients.SkipReleasesBelow(t, "stable/ocata") - clients.RequireAdmin(t) - - client, err := clients.NewPlacementV1Client() - th.AssertNoErr(t, err) client.Microversion = "1.1" - _, err = resourceproviders.GetAggregates(context.TODO(), client, "00000000-0000-0000-0000-000000000000").Extract() th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } -func TestResourceProviderAggregatesUpdateSuccess(t *testing.T) { - // resource_provider_generation is required in the PUT request body from microversion 1.19. +func TestResourceProviderUpdateAggregates(t *testing.T) { clients.SkipReleasesBelow(t, "stable/ocata") clients.RequireAdmin(t) @@ -558,8 +532,7 @@ func TestResourceProviderAggregatesUpdateSuccess(t *testing.T) { } } -func TestResourceProviderAggregatesUpdateNegative(t *testing.T) { - // resource_provider_generation is required in the PUT request body from microversion 1.19. +func TestResourceProviderUpdateAggregateMismatch(t *testing.T) { clients.SkipReleasesBelow(t, "stable/ocata") clients.RequireAdmin(t) @@ -588,8 +561,7 @@ func TestResourceProviderAggregatesUpdateNegative(t *testing.T) { th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusConflict)) } -func TestResourceProviderAggregatesUpdatePreGenerationSuccess(t *testing.T) { - // Before microversion 1.19, the PUT request body is just a list of aggregate UUIDs. +func TestResourceProviderUpdateAggregatesPreGeneration(t *testing.T) { clients.SkipReleasesBelow(t, "stable/ocata") clients.RequireAdmin(t) @@ -621,7 +593,7 @@ func TestResourceProviderAggregatesUpdatePreGenerationSuccess(t *testing.T) { } } -func TestResourceProviderAggregatesUpdatePreGenerationWithGenerationSuccess(t *testing.T) { +func TestResourceProviderUpdateAggregatesPreGenerationWithGenerationSuccess(t *testing.T) { // Before microversion 1.19, ResourceProviderGeneration in opts is silently stripped from // the request body, so the operation must succeed even when the caller supplies it. clients.SkipReleasesBelow(t, "stable/ocata") diff --git a/openstack/placement/v1/resourceproviders/requests.go b/openstack/placement/v1/resourceproviders/requests.go index f71bfe8519..aecc975060 100644 --- a/openstack/placement/v1/resourceproviders/requests.go +++ b/openstack/placement/v1/resourceproviders/requests.go @@ -4,6 +4,7 @@ import ( "context" "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/openstack/utils" "github.com/gophercloud/gophercloud/v2/pagination" ) @@ -286,8 +287,16 @@ func UpdateAggregates(ctx context.Context, client *gophercloud.ServiceClient, re } var body any = b - if useGenerations := microversionAtLeast(client, 1, 19); !useGenerations { - body = b["aggregates"] + if client.Microversion != "" { + _, minor, err := utils.ParseMicroversion(client.Microversion) + if err != nil { + r.Err = err + return + } + // In microversions prior to 1.19, the body was not enveloped. + if minor < 19 { + body = b["aggregates"] + } } resp, err := client.Put(ctx, updateResourceProviderAggregatesURL(client, resourceProviderID), body, &r.Body, &gophercloud.RequestOpts{ OkCodes: []int{200}, diff --git a/openstack/placement/v1/resourceproviders/util.go b/openstack/placement/v1/resourceproviders/util.go deleted file mode 100644 index ecddaed8ea..0000000000 --- a/openstack/placement/v1/resourceproviders/util.go +++ /dev/null @@ -1,14 +0,0 @@ -package resourceproviders - -import ( - "github.com/gophercloud/gophercloud/v2" - "github.com/gophercloud/gophercloud/v2/openstack/utils" -) - -func microversionAtLeast(client *gophercloud.ServiceClient, major, minor int) bool { - M, m, err := utils.ParseMicroversion(client.Microversion) - if err != nil { - return false - } - return M > major || (M == major && m >= minor) -} From be391f3ddde959eb418c5cbbaba044a7d165eecf Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 9 Apr 2026 16:30:48 +0100 Subject: [PATCH 375/429] ci: Make "Aetos on OpenStack master" non-voting Sync our script with current configuration. Signed-off-by: Stephen Finucane --- script/configure-required-github-jobs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/script/configure-required-github-jobs b/script/configure-required-github-jobs index bb4412961d..5f431c65fb 100755 --- a/script/configure-required-github-jobs +++ b/script/configure-required-github-jobs @@ -55,6 +55,9 @@ declare -A EXPECTED_SETTINGS=( # their workflow has an `on: merge_group` trigger. Add entries using the exact # name format: "" (with resolved matrix values). SKIP_CHECKS=( + # FIXME(stephenfin): Re-enable this once [1] merges + # [1] https://review.opendev.org/c/openstack/project-config/+/983728 + "Aetos on OpenStack master" "finish" # coveralls parallel-finish job, not a test gate ) From 376810ab3f76fa00f43e850f9db9811481c28b5d Mon Sep 17 00:00:00 2001 From: Dominik Danelski Date: Fri, 10 Apr 2026 15:01:39 +0200 Subject: [PATCH 376/429] Implement Placement allocations GET Related #526 API reference: https://docs.openstack.org/api-ref/placement/?expanded=#list-allocations Code reference: https://opendev.org/openstack/placement/src/branch/stable/2026.1/placement/handlers/allocation.py#L260-L286 --- .../placement/v1/allocations_test.go | 29 +++++ openstack/placement/v1/allocations/doc.go | 15 +++ .../placement/v1/allocations/requests.go | 14 +++ openstack/placement/v1/allocations/results.go | 46 ++++++++ .../placement/v1/allocations/testing/doc.go | 2 + .../v1/allocations/testing/fixtures_test.go | 110 ++++++++++++++++++ .../v1/allocations/testing/requests_test.go | 32 +++++ openstack/placement/v1/allocations/urls.go | 7 ++ 8 files changed, 255 insertions(+) create mode 100644 internal/acceptance/openstack/placement/v1/allocations_test.go create mode 100644 openstack/placement/v1/allocations/doc.go create mode 100644 openstack/placement/v1/allocations/requests.go create mode 100644 openstack/placement/v1/allocations/results.go create mode 100644 openstack/placement/v1/allocations/testing/doc.go create mode 100644 openstack/placement/v1/allocations/testing/fixtures_test.go create mode 100644 openstack/placement/v1/allocations/testing/requests_test.go create mode 100644 openstack/placement/v1/allocations/urls.go diff --git a/internal/acceptance/openstack/placement/v1/allocations_test.go b/internal/acceptance/openstack/placement/v1/allocations_test.go new file mode 100644 index 0000000000..71452221f2 --- /dev/null +++ b/internal/acceptance/openstack/placement/v1/allocations_test.go @@ -0,0 +1,29 @@ +//go:build acceptance || placement || allocations + +package v1 + +import ( + "context" + "fmt" + "math/rand" + "testing" + + "github.com/gophercloud/gophercloud/v2/internal/acceptance/clients" + "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/allocations" + th "github.com/gophercloud/gophercloud/v2/testhelper" +) + +func TestGetAllocationsSuccess(t *testing.T) { + clients.RequireAdmin(t) + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + consumerUUID := fmt.Sprintf("%08x-0000-0000-0000-000000000000", rand.Int31()) + + // Assert: We don't have any allocations for this random UUID. + // We get an empty allocations map, not 404. + allocs, err := allocations.Get(context.TODO(), client, consumerUUID).Extract() + th.AssertNoErr(t, err) + th.AssertEquals(t, 0, len(allocs.Allocations)) +} diff --git a/openstack/placement/v1/allocations/doc.go b/openstack/placement/v1/allocations/doc.go new file mode 100644 index 0000000000..9851f50e01 --- /dev/null +++ b/openstack/placement/v1/allocations/doc.go @@ -0,0 +1,15 @@ +/* +Package allocations manages consumer allocations from the OpenStack Placement service. + +Allocation API requests are available starting from microversion 1.0. + +# Example to get allocations for a consumer + + allocs, err := allocations.Get(context.TODO(), placementClient, consumerUUID).Extract() + if err != nil { + panic(err) + } + + fmt.Printf("%+v\n", allocs) +*/ +package allocations diff --git a/openstack/placement/v1/allocations/requests.go b/openstack/placement/v1/allocations/requests.go new file mode 100644 index 0000000000..8e4dd8dfb9 --- /dev/null +++ b/openstack/placement/v1/allocations/requests.go @@ -0,0 +1,14 @@ +package allocations + +import ( + "context" + + "github.com/gophercloud/gophercloud/v2" +) + +// Get retrieves the allocations for a specific consumer by its UUID. +func Get(ctx context.Context, client *gophercloud.ServiceClient, consumerUUID string) (r GetResult) { + resp, err := client.Get(ctx, getURL(client, consumerUUID), &r.Body, nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} diff --git a/openstack/placement/v1/allocations/results.go b/openstack/placement/v1/allocations/results.go new file mode 100644 index 0000000000..01d91713b3 --- /dev/null +++ b/openstack/placement/v1/allocations/results.go @@ -0,0 +1,46 @@ +package allocations + +import "github.com/gophercloud/gophercloud/v2" + +// ProviderAllocations represents the per-provider portion of an allocations response. +type ProviderAllocations struct { + Generation int `json:"generation"` + + // Resources maps resource class names to the integer amount consumed from the provider. + Resources map[string]int `json:"resources"` +} + +// Allocations represents the allocations for a single consumer. +// The Allocations field maps resource provider UUIDs to ProviderAllocations, +// describing how much of each resource class is consumed from each provider. +type Allocations struct { + // Allocations maps resource provider UUIDs to the resources consumed from each. + Allocations map[string]ProviderAllocations `json:"allocations"` + + // Available from microversion 1.12. + // Will be absent when listing allocations for a consumer UUID that has no allocations. + ProjectID *string `json:"project_id"` + + // Available from microversion 1.12. + // Will be absent when listing allocations for a consumer UUID that has no allocations. + UserID *string `json:"user_id"` + + // Available from microversion 1.28. + ConsumerGeneration *int `json:"consumer_generation"` + + // Available from microversion 1.38. + ConsumerType *string `json:"consumer_type"` +} + +// GetResult is the result of a Get operation. Call its Extract method +// to interpret it as an Allocations. +type GetResult struct { + gophercloud.Result +} + +// Extract interprets a GetResult as Allocations. +func (r GetResult) Extract() (*Allocations, error) { + var s Allocations + err := r.ExtractInto(&s) + return &s, err +} diff --git a/openstack/placement/v1/allocations/testing/doc.go b/openstack/placement/v1/allocations/testing/doc.go new file mode 100644 index 0000000000..a06432adf8 --- /dev/null +++ b/openstack/placement/v1/allocations/testing/doc.go @@ -0,0 +1,2 @@ +// Package testing contains allocations unit tests. +package testing diff --git a/openstack/placement/v1/allocations/testing/fixtures_test.go b/openstack/placement/v1/allocations/testing/fixtures_test.go new file mode 100644 index 0000000000..0cc47e1816 --- /dev/null +++ b/openstack/placement/v1/allocations/testing/fixtures_test.go @@ -0,0 +1,110 @@ +package testing + +import ( + "fmt" + "net/http" + "testing" + + "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/allocations" + th "github.com/gophercloud/gophercloud/v2/testhelper" + "github.com/gophercloud/gophercloud/v2/testhelper/client" +) + +const ConsumerUUID = "ba8f2c8e-0bf7-4a32-aacf-7c11f7f9a321" +const EmptyConsumerUUID = "00000000-0000-0000-0000-000000000000" +const ProviderUUID1 = "7d4f1abe-2f91-4f7a-8872-b70d9fb5c3dd" +const ProviderUUID2 = "f3f97e00-13e1-4c88-a7cd-db3bb4f99357" +const ProjectID = "42a2b0fa980d4f7f873e8f0d8b4e1b0e" +const UserID = "b29d880b2c114d5d9a55748b26b2e41e" + +var GetAllocationsBody = fmt.Sprintf(` +{ + "allocations": { + "%s": { + "generation": 3, + "resources": { + "VCPU": 2, + "MEMORY_MB": 2048 + } + }, + "%s": { + "generation": 7, + "resources": { + "DISK_GB": 50 + } + } + }, + "project_id": "%s", + "user_id": "%s", + "consumer_generation": 2, + "consumer_type": "INSTANCE" +} +`, ProviderUUID1, ProviderUUID2, ProjectID, UserID) + +// GetEmptyAllocationsBody is the response for a consumer UUID that has no +// allocations. Per the Placement API, only the "allocations" key is present; +// project_id, user_id, consumer_generation, and consumer_type are absent. +const GetEmptyAllocationsBody = ` +{ + "allocations": {} +} +` + +var consumerGeneration = 2 +var consumerType = "INSTANCE" +var projectID = ProjectID +var userID = UserID + +var ExpectedAllocations = allocations.Allocations{ + Allocations: map[string]allocations.ProviderAllocations{ + ProviderUUID1: { + Generation: 3, + Resources: map[string]int{ + "VCPU": 2, + "MEMORY_MB": 2048, + }, + }, + ProviderUUID2: { + Generation: 7, + Resources: map[string]int{ + "DISK_GB": 50, + }, + }, + }, + ProjectID: &projectID, + UserID: &userID, + ConsumerGeneration: &consumerGeneration, + ConsumerType: &consumerType, +} + +var ExpectedEmptyAllocations = allocations.Allocations{ + Allocations: map[string]allocations.ProviderAllocations{}, +} + +func HandleGetAllocationsSuccess(t *testing.T, fakeServer th.FakeServer) { + url := fmt.Sprintf("/allocations/%s", ConsumerUUID) + + fakeServer.Mux.HandleFunc(url, func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, GetAllocationsBody) + }) +} + +func HandleGetEmptyAllocationsSuccess(t *testing.T, fakeServer th.FakeServer) { + url := fmt.Sprintf("/allocations/%s", EmptyConsumerUUID) + + fakeServer.Mux.HandleFunc(url, func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, GetEmptyAllocationsBody) + }) +} diff --git a/openstack/placement/v1/allocations/testing/requests_test.go b/openstack/placement/v1/allocations/testing/requests_test.go new file mode 100644 index 0000000000..9ee5a736c9 --- /dev/null +++ b/openstack/placement/v1/allocations/testing/requests_test.go @@ -0,0 +1,32 @@ +package testing + +import ( + "context" + "testing" + + "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/allocations" + th "github.com/gophercloud/gophercloud/v2/testhelper" + "github.com/gophercloud/gophercloud/v2/testhelper/client" +) + +func TestGetSuccess(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleGetAllocationsSuccess(t, fakeServer) + + actual, err := allocations.Get(context.TODO(), client.ServiceClient(fakeServer), ConsumerUUID).Extract() + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedAllocations, *actual) +} + +func TestGetEmptySuccess(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleGetEmptyAllocationsSuccess(t, fakeServer) + + actual, err := allocations.Get(context.TODO(), client.ServiceClient(fakeServer), EmptyConsumerUUID).Extract() + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedEmptyAllocations, *actual) +} diff --git a/openstack/placement/v1/allocations/urls.go b/openstack/placement/v1/allocations/urls.go new file mode 100644 index 0000000000..f1deebb82e --- /dev/null +++ b/openstack/placement/v1/allocations/urls.go @@ -0,0 +1,7 @@ +package allocations + +import "github.com/gophercloud/gophercloud/v2" + +func getURL(client *gophercloud.ServiceClient, consumerUUID string) string { + return client.ServiceURL("allocations", consumerUUID) +} From 6991fdf3f85a249760e3bd763926f9f987c8338f Mon Sep 17 00:00:00 2001 From: Dominik Danelski Date: Fri, 10 Apr 2026 15:15:01 +0200 Subject: [PATCH 377/429] Implement Placement allocations PUT Related #526 API reference: https://docs.openstack.org/api-ref/placement/?expanded=#update-allocations Code reference: https://opendev.org/openstack/placement/src/branch/stable/2026.1/placement/handlers/allocation.py#L391-L413 --- .../placement/v1/allocations_test.go | 163 ++++++++++++++++++ .../openstack/placement/v1/placement.go | 43 +++++ openstack/placement/v1/allocations/doc.go | 49 ++++++ .../placement/v1/allocations/requests.go | 63 +++++++ openstack/placement/v1/allocations/results.go | 6 + .../v1/allocations/testing/fixtures_test.go | 130 ++++++++++++++ .../v1/allocations/testing/requests_test.go | 69 ++++++++ openstack/placement/v1/allocations/urls.go | 4 + 8 files changed, 527 insertions(+) diff --git a/internal/acceptance/openstack/placement/v1/allocations_test.go b/internal/acceptance/openstack/placement/v1/allocations_test.go index 71452221f2..bb2297eb48 100644 --- a/internal/acceptance/openstack/placement/v1/allocations_test.go +++ b/internal/acceptance/openstack/placement/v1/allocations_test.go @@ -6,9 +6,12 @@ import ( "context" "fmt" "math/rand" + "net/http" "testing" + "github.com/gophercloud/gophercloud/v2" "github.com/gophercloud/gophercloud/v2/internal/acceptance/clients" + "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/allocations" th "github.com/gophercloud/gophercloud/v2/testhelper" ) @@ -27,3 +30,163 @@ func TestGetAllocationsSuccess(t *testing.T) { th.AssertNoErr(t, err) th.AssertEquals(t, 0, len(allocs.Allocations)) } + +func TestUpdateAllocationsNewConsumerSuccess(t *testing.T) { + clients.RequireAdmin(t) + clients.SkipReleasesBelow(t, "stable/rocky") + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + resourceProvider, _, err := CreateResourceProviderWithVCPUInventory(t, client) + th.AssertNoErr(t, err) + defer DeleteResourceProvider(t, client, resourceProvider.UUID) + + consumerUUID := fmt.Sprintf("%08x-0000-0000-0000-000000000000", rand.Int31()) + + client.Microversion = "1.28" + + // Act: Update with nil ConsumerGeneration to signal a new consumer (serialized as JSON null, not omitted). + err = allocations.Update(context.TODO(), client, consumerUUID, allocations.UpdateOpts{ + Allocations: map[string]allocations.ProviderAllocationsOpts{ + resourceProvider.UUID: { + Resources: map[string]int{"VCPU": 2, "MEMORY_MB": 1024}, + }, + }, + ProjectID: "test-project", + UserID: "test-user", + ConsumerGeneration: nil, + }).ExtractErr() + th.AssertNoErr(t, err) + + allocs, err := allocations.Get(context.TODO(), client, consumerUUID).Extract() + th.AssertNoErr(t, err) + th.AssertEquals(t, 1, len(allocs.Allocations)) + th.AssertEquals(t, 2, allocs.Allocations[resourceProvider.UUID].Resources["VCPU"]) + th.AssertEquals(t, 1024, allocs.Allocations[resourceProvider.UUID].Resources["MEMORY_MB"]) + + // Clean up: remove allocations using PUT with empty allocations and the + // current generation (safe deletion, recommended over DELETE). + err = allocations.Update(context.TODO(), client, consumerUUID, allocations.UpdateOpts{ + Allocations: map[string]allocations.ProviderAllocationsOpts{}, + ProjectID: "test-project", + UserID: "test-user", + ConsumerGeneration: allocs.ConsumerGeneration, + }).ExtractErr() + th.AssertNoErr(t, err) +} + +func TestUpdateAllocationsSuccess(t *testing.T) { + clients.RequireAdmin(t) + clients.SkipReleasesBelow(t, "stable/rocky") + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + resourceProvider, _, err := CreateResourceProviderWithVCPUInventory(t, client) + th.AssertNoErr(t, err) + defer DeleteResourceProvider(t, client, resourceProvider.UUID) + + consumerUUID := fmt.Sprintf("%08x-0000-0000-0000-000000000001", rand.Int31()) + + client.Microversion = "1.28" + + // Arrange: Create the consumer with nil ConsumerGeneration. + err = allocations.Update(context.TODO(), client, consumerUUID, allocations.UpdateOpts{ + Allocations: map[string]allocations.ProviderAllocationsOpts{ + resourceProvider.UUID: { + Resources: map[string]int{"VCPU": 1}, + }, + }, + ProjectID: "test-project", + UserID: "test-user", + ConsumerGeneration: nil, + }).ExtractErr() + th.AssertNoErr(t, err) + + existing, err := allocations.Get(context.TODO(), client, consumerUUID).Extract() + th.AssertNoErr(t, err) + + // Act: Update allocations using the consumer's current generation. + err = allocations.Update(context.TODO(), client, consumerUUID, allocations.UpdateOpts{ + Allocations: map[string]allocations.ProviderAllocationsOpts{ + resourceProvider.UUID: { + Resources: map[string]int{"VCPU": 2, "MEMORY_MB": 1024}, + }, + }, + ProjectID: *existing.ProjectID, + UserID: *existing.UserID, + ConsumerGeneration: existing.ConsumerGeneration, + }).ExtractErr() + th.AssertNoErr(t, err) + + updated, err := allocations.Get(context.TODO(), client, consumerUUID).Extract() + th.AssertNoErr(t, err) + th.AssertEquals(t, 2, updated.Allocations[resourceProvider.UUID].Resources["VCPU"]) + th.AssertEquals(t, 1024, updated.Allocations[resourceProvider.UUID].Resources["MEMORY_MB"]) + + tools.PrintResource(t, updated) + + // Clean up. + err = allocations.Update(context.TODO(), client, consumerUUID, allocations.UpdateOpts{ + Allocations: map[string]allocations.ProviderAllocationsOpts{}, + ProjectID: updated.ProjectID, + UserID: updated.UserID, + ConsumerGeneration: updated.ConsumerGeneration, + }).ExtractErr() + th.AssertNoErr(t, err) +} + +func TestUpdateAllocationsConflict(t *testing.T) { + clients.RequireAdmin(t) + clients.SkipReleasesBelow(t, "stable/rocky") + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + resourceProvider, _, err := CreateResourceProviderWithVCPUInventory(t, client) + th.AssertNoErr(t, err) + defer DeleteResourceProvider(t, client, resourceProvider.UUID) + + consumerUUID := fmt.Sprintf("%08x-0000-0000-0000-000000000002", rand.Int31()) + + client.Microversion = "1.28" + + // Arrange: Create the consumer to establish a valid generation. + err = allocations.Update(context.TODO(), client, consumerUUID, allocations.UpdateOpts{ + Allocations: map[string]allocations.ProviderAllocationsOpts{ + resourceProvider.UUID: { + Resources: map[string]int{"VCPU": 1}, + }, + }, + ProjectID: "test-project", + UserID: "test-user", + ConsumerGeneration: nil, + }).ExtractErr() + th.AssertNoErr(t, err) + + // Act: Update with a stale generation to trigger a 409 conflict. + staleGeneration := -1 + err = allocations.Update(context.TODO(), client, consumerUUID, allocations.UpdateOpts{ + Allocations: map[string]allocations.ProviderAllocationsOpts{ + resourceProvider.UUID: { + Resources: map[string]int{"VCPU": 2}, + }, + }, + ProjectID: "test-project", + UserID: "test-user", + ConsumerGeneration: &staleGeneration, + }).ExtractErr() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusConflict)) + + // Clean up with correct generation. + existing, err := allocations.Get(context.TODO(), client, consumerUUID).Extract() + th.AssertNoErr(t, err) + err = allocations.Update(context.TODO(), client, consumerUUID, allocations.UpdateOpts{ + Allocations: map[string]allocations.ProviderAllocationsOpts{}, + ProjectID: *existing.ProjectID, + UserID: *existing.UserID, + ConsumerGeneration: existing.ConsumerGeneration, + }).ExtractErr() + th.AssertNoErr(t, err) +} diff --git a/internal/acceptance/openstack/placement/v1/placement.go b/internal/acceptance/openstack/placement/v1/placement.go index 4149d5ff8b..18c3304075 100644 --- a/internal/acceptance/openstack/placement/v1/placement.go +++ b/internal/acceptance/openstack/placement/v1/placement.go @@ -69,3 +69,46 @@ func DeleteResourceProvider(t *testing.T, client *gophercloud.ServiceClient, res t.Logf("Deleted resourceProvider: %s.", resourceProviderID) } + +// CreateResourceProviderWithVCPUInventory creates a resource provider and seeds it +// with a VCPU inventory, returning the provider and the inventory generation. +// This is used by acceptance tests that need a resource provider with available +// capacity before setting allocations against it. +func CreateResourceProviderWithVCPUInventory(t *testing.T, client *gophercloud.ServiceClient) (*resourceproviders.ResourceProvider, int, error) { + resourceProvider, err := CreateResourceProvider(t, client) + if err != nil { + return nil, 0, err + } + + inventories, err := resourceproviders.GetInventories(context.TODO(), client, resourceProvider.UUID).Extract() + if err != nil { + return nil, 0, err + } + + updatedInventories, err := resourceproviders.UpdateInventories(context.TODO(), client, resourceProvider.UUID, resourceproviders.UpdateInventoriesOpts{ + ResourceProviderGeneration: inventories.ResourceProviderGeneration, + Inventories: map[string]resourceproviders.Inventory{ + "VCPU": { + AllocationRatio: 1.0, + MaxUnit: 8, + MinUnit: 1, + Reserved: 0, + StepSize: 1, + Total: 8, + }, + "MEMORY_MB": { + AllocationRatio: 1.0, + MaxUnit: 8192, + MinUnit: 1, + Reserved: 0, + StepSize: 1, + Total: 8192, + }, + }, + }).Extract() + if err != nil { + return nil, 0, err + } + + return resourceProvider, updatedInventories.ResourceProviderGeneration, nil +} diff --git a/openstack/placement/v1/allocations/doc.go b/openstack/placement/v1/allocations/doc.go index 9851f50e01..769c114258 100644 --- a/openstack/placement/v1/allocations/doc.go +++ b/openstack/placement/v1/allocations/doc.go @@ -11,5 +11,54 @@ Allocation API requests are available starting from microversion 1.0. } fmt.Printf("%+v\n", allocs) + +# Example to set allocations for a new consumer (microversion 1.28+) + +When creating allocations for a consumer that does not yet exist, set +ConsumerGeneration to nil. It will be serialized as JSON null, telling the +server that no prior allocation is expected. This is different from omitting +the field: nil is required, not optional. + + placementClient.Microversion = "1.28" + + err := allocations.Update(context.TODO(), placementClient, consumerUUID, allocations.UpdateOpts{ + Allocations: map[string]allocations.ProviderAllocationsOpts{ + providerUUID: { + Resources: map[string]int{"VCPU": 2, "MEMORY_MB": 2048}, + }, + }, + ProjectID: projectID, + UserID: userID, + ConsumerGeneration: nil, + }).ExtractErr() + if err != nil { + panic(err) + } + +# Example to update allocations for an existing consumer (microversion 1.28+) + +When updating allocations for an existing consumer, retrieve the current +generation first and pass it in. + + placementClient.Microversion = "1.28" + + existing, err := allocations.Get(context.TODO(), placementClient, consumerUUID).Extract() + if err != nil { + panic(err) + } + + err = allocations.Update(context.TODO(), placementClient, consumerUUID, allocations.UpdateOpts{ + Allocations: map[string]allocations.ProviderAllocationsOpts{ + providerUUID: { + Resources: map[string]int{"VCPU": 4, "MEMORY_MB": 4096}, + }, + }, + ProjectID: *existing.ProjectID, + UserID: *existing.UserID, + ConsumerGeneration: existing.ConsumerGeneration, + }).ExtractErr() + if err != nil { + panic(err) + } */ package allocations diff --git a/openstack/placement/v1/allocations/requests.go b/openstack/placement/v1/allocations/requests.go index 8e4dd8dfb9..0996df58c1 100644 --- a/openstack/placement/v1/allocations/requests.go +++ b/openstack/placement/v1/allocations/requests.go @@ -12,3 +12,66 @@ func Get(ctx context.Context, client *gophercloud.ServiceClient, consumerUUID st _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return } + +// ProviderAllocationsOpts specifies the resources to consume from a single resource +// provider in a write request. +type ProviderAllocationsOpts struct { + // Resources maps resource class names to the integer amount to consume. + Resources map[string]int `json:"resources"` +} + +// UpdateOptsBuilder allows extensions to add additional parameters to the +// Update request. +type UpdateOptsBuilder interface { + ToAllocationUpdateMap() (map[string]any, error) +} + +// UpdateOpts specifies the allocation to be set for a consumer. +// +// This requires microversion 1.28 or later. Write operations on allocations +// using earlier microversions are not safe in concurrent environments. +// +// ConsumerGeneration must be set to nil when creating allocations for a new +// consumer (it serializes as JSON null, which signals to the server that no +// prior allocation is expected). For an existing consumer, set it to the +// generation value returned by a prior Get call. A mismatch causes a 409 +// Conflict response, allowing the caller to retry safely. +type UpdateOpts struct { + // Allocations maps resource provider UUIDs to the resources to consume. + Allocations map[string]ProviderAllocationsOpts `json:"allocations"` + + // Required from microversion 1.8. + ProjectID string `json:"project_id"` + + // Required from microversion 1.8. + UserID string `json:"user_id"` + + // ConsumerGeneration must be nil for new consumers (serializes as null) or + // the current generation for existing consumers. + // See the UpdateOpts type documentation for details. + ConsumerGeneration *int `json:"consumer_generation"` + + // Required from microversion 1.38. + ConsumerType string `json:"consumer_type,omitempty"` +} + +// ToAllocationUpdateMap constructs a request body from UpdateOpts. +func (opts UpdateOpts) ToAllocationUpdateMap() (map[string]any, error) { + return gophercloud.BuildRequestBody(opts, "") +} + +// Update replaces all allocations for a consumer. The operation is atomic. +// +// Requires microversion 1.28 or later. +func Update(ctx context.Context, client *gophercloud.ServiceClient, consumerUUID string, opts UpdateOptsBuilder) (r UpdateResult) { + b, err := opts.ToAllocationUpdateMap() + if err != nil { + r.Err = err + return + } + resp, err := client.Put(ctx, updateURL(client, consumerUUID), b, nil, &gophercloud.RequestOpts{ + OkCodes: []int{204}, + }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} diff --git a/openstack/placement/v1/allocations/results.go b/openstack/placement/v1/allocations/results.go index 01d91713b3..ce5775df81 100644 --- a/openstack/placement/v1/allocations/results.go +++ b/openstack/placement/v1/allocations/results.go @@ -44,3 +44,9 @@ func (r GetResult) Extract() (*Allocations, error) { err := r.ExtractInto(&s) return &s, err } + +// UpdateResult is the result of an Update operation. Call its ExtractErr +// method to determine if the request succeeded or failed. +type UpdateResult struct { + gophercloud.ErrResult +} diff --git a/openstack/placement/v1/allocations/testing/fixtures_test.go b/openstack/placement/v1/allocations/testing/fixtures_test.go index 0cc47e1816..cc329aa2b1 100644 --- a/openstack/placement/v1/allocations/testing/fixtures_test.go +++ b/openstack/placement/v1/allocations/testing/fixtures_test.go @@ -12,6 +12,7 @@ import ( const ConsumerUUID = "ba8f2c8e-0bf7-4a32-aacf-7c11f7f9a321" const EmptyConsumerUUID = "00000000-0000-0000-0000-000000000000" +const ConflictConsumerUUID = "ffffffff-ffff-ffff-ffff-ffffffffffff" const ProviderUUID1 = "7d4f1abe-2f91-4f7a-8872-b70d9fb5c3dd" const ProviderUUID2 = "f3f97e00-13e1-4c88-a7cd-db3bb4f99357" const ProjectID = "42a2b0fa980d4f7f873e8f0d8b4e1b0e" @@ -81,6 +82,72 @@ var ExpectedEmptyAllocations = allocations.Allocations{ Allocations: map[string]allocations.ProviderAllocations{}, } +var UpdateAllocationsRequest = fmt.Sprintf(` +{ + "allocations": { + "%s": { + "resources": { + "VCPU": 2, + "MEMORY_MB": 2048 + } + } + }, + "project_id": "%s", + "user_id": "%s", + "consumer_generation": null +} +`, ProviderUUID1, ProjectID, UserID) + +var UpdateAllocationsExistingRequest = fmt.Sprintf(` +{ + "allocations": { + "%s": { + "resources": { + "VCPU": 2, + "MEMORY_MB": 2048 + } + } + }, + "project_id": "%s", + "user_id": "%s", + "consumer_generation": 1 +} +`, ProviderUUID1, ProjectID, UserID) + +var GetAllocationsAfterUpdateBody = fmt.Sprintf(` +{ + "allocations": { + "%s": { + "generation": 4, + "resources": { + "VCPU": 2, + "MEMORY_MB": 2048 + } + } + }, + "project_id": "%s", + "user_id": "%s", + "consumer_generation": 1 +} +`, ProviderUUID1, ProjectID, UserID) + +var consumerGenerationAfterUpdate = 1 + +var ExpectedAllocationsAfterUpdate = allocations.Allocations{ + Allocations: map[string]allocations.ProviderAllocations{ + ProviderUUID1: { + Generation: 4, + Resources: map[string]int{ + "VCPU": 2, + "MEMORY_MB": 2048, + }, + }, + }, + ProjectID: &projectID, + UserID: &userID, + ConsumerGeneration: &consumerGenerationAfterUpdate, +} + func HandleGetAllocationsSuccess(t *testing.T, fakeServer th.FakeServer) { url := fmt.Sprintf("/allocations/%s", ConsumerUUID) @@ -108,3 +175,66 @@ func HandleGetEmptyAllocationsSuccess(t *testing.T, fakeServer th.FakeServer) { fmt.Fprint(w, GetEmptyAllocationsBody) }) } + +// HandleUpdateAndGetAllocationsSuccess handles PUT followed by GET on the same URL, +// branching by HTTP method. +func HandleUpdateAndGetAllocationsSuccess(t *testing.T, fakeServer th.FakeServer) { + url := fmt.Sprintf("/allocations/%s", ConsumerUUID) + + fakeServer.Mux.HandleFunc(url, func(w http.ResponseWriter, r *http.Request) { + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + switch r.Method { + case http.MethodPut: + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestJSONRequest(t, r, UpdateAllocationsRequest) + w.WriteHeader(http.StatusNoContent) + case http.MethodGet: + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + fmt.Fprint(w, GetAllocationsAfterUpdateBody) + default: + t.Fatalf("unexpected method: %s", r.Method) + } + }) +} + +// HandleUpdateAllocationsNewConsumerSuccess handles PUT with nil consumer_generation +// (new consumer case), verifying that null is sent in the request body. +func HandleUpdateAllocationsNewConsumerSuccess(t *testing.T, fakeServer th.FakeServer) { + url := fmt.Sprintf("/allocations/%s", EmptyConsumerUUID) + + fakeServer.Mux.HandleFunc(url, func(w http.ResponseWriter, r *http.Request) { + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + switch r.Method { + case http.MethodPut: + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestJSONRequest(t, r, UpdateAllocationsRequest) + w.WriteHeader(http.StatusNoContent) + case http.MethodGet: + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + fmt.Fprint(w, GetAllocationsAfterUpdateBody) + default: + t.Fatalf("unexpected method: %s", r.Method) + } + }) +} + +// HandleUpdateAllocationsConflict simulates a 409 when the consumer_generation +// in the request does not match the server's current value. +func HandleUpdateAllocationsConflict(t *testing.T, fakeServer th.FakeServer) { + url := fmt.Sprintf("/allocations/%s", ConflictConsumerUUID) + + fakeServer.Mux.HandleFunc(url, func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "PUT") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusConflict) + fmt.Fprint(w, `{"errors":[{"status":409,"title":"Conflict","code":"placement.concurrent_update"}]}`) + }) +} diff --git a/openstack/placement/v1/allocations/testing/requests_test.go b/openstack/placement/v1/allocations/testing/requests_test.go index 9ee5a736c9..510fd78195 100644 --- a/openstack/placement/v1/allocations/testing/requests_test.go +++ b/openstack/placement/v1/allocations/testing/requests_test.go @@ -2,8 +2,10 @@ package testing import ( "context" + "net/http" "testing" + "github.com/gophercloud/gophercloud/v2" "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/allocations" th "github.com/gophercloud/gophercloud/v2/testhelper" "github.com/gophercloud/gophercloud/v2/testhelper/client" @@ -30,3 +32,70 @@ func TestGetEmptySuccess(t *testing.T) { th.AssertNoErr(t, err) th.AssertDeepEquals(t, ExpectedEmptyAllocations, *actual) } + +func TestUpdateSuccess(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleUpdateAndGetAllocationsSuccess(t, fakeServer) + + err := allocations.Update(context.TODO(), client.ServiceClient(fakeServer), ConsumerUUID, allocations.UpdateOpts{ + Allocations: map[string]allocations.ProviderAllocationsOpts{ + ProviderUUID1: { + Resources: map[string]int{"VCPU": 2, "MEMORY_MB": 2048}, + }, + }, + ProjectID: ProjectID, + UserID: UserID, + ConsumerGeneration: nil, + }).ExtractErr() + th.AssertNoErr(t, err) + + actual, err := allocations.Get(context.TODO(), client.ServiceClient(fakeServer), ConsumerUUID).Extract() + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedAllocationsAfterUpdate, *actual) +} + +func TestUpdateNewConsumerSuccess(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleUpdateAllocationsNewConsumerSuccess(t, fakeServer) + + // Act: Update with nil ConsumerGeneration; it must be serialized as JSON null, not omitted. + err := allocations.Update(context.TODO(), client.ServiceClient(fakeServer), EmptyConsumerUUID, allocations.UpdateOpts{ + Allocations: map[string]allocations.ProviderAllocationsOpts{ + ProviderUUID1: { + Resources: map[string]int{"VCPU": 2, "MEMORY_MB": 2048}, + }, + }, + ProjectID: ProjectID, + UserID: UserID, + ConsumerGeneration: nil, + }).ExtractErr() + th.AssertNoErr(t, err) + + actual, err := allocations.Get(context.TODO(), client.ServiceClient(fakeServer), EmptyConsumerUUID).Extract() + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedAllocationsAfterUpdate, *actual) +} + +func TestUpdateConflict(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleUpdateAllocationsConflict(t, fakeServer) + + staleGeneration := 0 + err := allocations.Update(context.TODO(), client.ServiceClient(fakeServer), ConflictConsumerUUID, allocations.UpdateOpts{ + Allocations: map[string]allocations.ProviderAllocationsOpts{ + ProviderUUID1: { + Resources: map[string]int{"VCPU": 1}, + }, + }, + ProjectID: ProjectID, + UserID: UserID, + ConsumerGeneration: &staleGeneration, + }).ExtractErr() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusConflict)) +} diff --git a/openstack/placement/v1/allocations/urls.go b/openstack/placement/v1/allocations/urls.go index f1deebb82e..93c43d3c66 100644 --- a/openstack/placement/v1/allocations/urls.go +++ b/openstack/placement/v1/allocations/urls.go @@ -5,3 +5,7 @@ import "github.com/gophercloud/gophercloud/v2" func getURL(client *gophercloud.ServiceClient, consumerUUID string) string { return client.ServiceURL("allocations", consumerUUID) } + +func updateURL(client *gophercloud.ServiceClient, consumerUUID string) string { + return client.ServiceURL("allocations", consumerUUID) +} From 0b535caa82a9645742feb39180325a470fb44d10 Mon Sep 17 00:00:00 2001 From: Dominik Danelski Date: Fri, 10 Apr 2026 15:21:55 +0200 Subject: [PATCH 378/429] Implement Placement allocations DELETE Related #526 API reference: https://docs.openstack.org/api-ref/placement/?expanded=#delete-allocations Code reference: https://opendev.org/openstack/placement/src/branch/stable/2026.1/placement/handlers/allocation.py#L376-L388 --- .../placement/v1/allocations_test.go | 76 +++++++++++++------ openstack/placement/v1/allocations/doc.go | 11 +++ .../placement/v1/allocations/requests.go | 12 +++ openstack/placement/v1/allocations/results.go | 6 ++ .../v1/allocations/testing/fixtures_test.go | 36 +++++++++ .../v1/allocations/testing/requests_test.go | 25 ++++++ openstack/placement/v1/allocations/urls.go | 4 + 7 files changed, 145 insertions(+), 25 deletions(-) diff --git a/internal/acceptance/openstack/placement/v1/allocations_test.go b/internal/acceptance/openstack/placement/v1/allocations_test.go index bb2297eb48..63716941e7 100644 --- a/internal/acceptance/openstack/placement/v1/allocations_test.go +++ b/internal/acceptance/openstack/placement/v1/allocations_test.go @@ -43,6 +43,7 @@ func TestUpdateAllocationsNewConsumerSuccess(t *testing.T) { defer DeleteResourceProvider(t, client, resourceProvider.UUID) consumerUUID := fmt.Sprintf("%08x-0000-0000-0000-000000000000", rand.Int31()) + defer allocations.Delete(context.TODO(), client, consumerUUID) client.Microversion = "1.28" @@ -64,16 +65,6 @@ func TestUpdateAllocationsNewConsumerSuccess(t *testing.T) { th.AssertEquals(t, 1, len(allocs.Allocations)) th.AssertEquals(t, 2, allocs.Allocations[resourceProvider.UUID].Resources["VCPU"]) th.AssertEquals(t, 1024, allocs.Allocations[resourceProvider.UUID].Resources["MEMORY_MB"]) - - // Clean up: remove allocations using PUT with empty allocations and the - // current generation (safe deletion, recommended over DELETE). - err = allocations.Update(context.TODO(), client, consumerUUID, allocations.UpdateOpts{ - Allocations: map[string]allocations.ProviderAllocationsOpts{}, - ProjectID: "test-project", - UserID: "test-user", - ConsumerGeneration: allocs.ConsumerGeneration, - }).ExtractErr() - th.AssertNoErr(t, err) } func TestUpdateAllocationsSuccess(t *testing.T) { @@ -88,6 +79,7 @@ func TestUpdateAllocationsSuccess(t *testing.T) { defer DeleteResourceProvider(t, client, resourceProvider.UUID) consumerUUID := fmt.Sprintf("%08x-0000-0000-0000-000000000001", rand.Int31()) + defer allocations.Delete(context.TODO(), client, consumerUUID) client.Microversion = "1.28" @@ -126,15 +118,6 @@ func TestUpdateAllocationsSuccess(t *testing.T) { th.AssertEquals(t, 1024, updated.Allocations[resourceProvider.UUID].Resources["MEMORY_MB"]) tools.PrintResource(t, updated) - - // Clean up. - err = allocations.Update(context.TODO(), client, consumerUUID, allocations.UpdateOpts{ - Allocations: map[string]allocations.ProviderAllocationsOpts{}, - ProjectID: updated.ProjectID, - UserID: updated.UserID, - ConsumerGeneration: updated.ConsumerGeneration, - }).ExtractErr() - th.AssertNoErr(t, err) } func TestUpdateAllocationsConflict(t *testing.T) { @@ -149,6 +132,7 @@ func TestUpdateAllocationsConflict(t *testing.T) { defer DeleteResourceProvider(t, client, resourceProvider.UUID) consumerUUID := fmt.Sprintf("%08x-0000-0000-0000-000000000002", rand.Int31()) + defer allocations.Delete(context.TODO(), client, consumerUUID) client.Microversion = "1.28" @@ -178,15 +162,57 @@ func TestUpdateAllocationsConflict(t *testing.T) { ConsumerGeneration: &staleGeneration, }).ExtractErr() th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusConflict)) +} - // Clean up with correct generation. - existing, err := allocations.Get(context.TODO(), client, consumerUUID).Extract() +func TestDeleteAllocationsSuccess(t *testing.T) { + clients.RequireAdmin(t) + clients.SkipReleasesBelow(t, "stable/rocky") + + client, err := clients.NewPlacementV1Client() th.AssertNoErr(t, err) + + resourceProvider, _, err := CreateResourceProviderWithVCPUInventory(t, client) + th.AssertNoErr(t, err) + defer DeleteResourceProvider(t, client, resourceProvider.UUID) + + consumerUUID := fmt.Sprintf("%08x-0000-0000-0000-000000000003", rand.Int31()) + + client.Microversion = "1.28" + + // Arrange: Create allocations for the consumer. err = allocations.Update(context.TODO(), client, consumerUUID, allocations.UpdateOpts{ - Allocations: map[string]allocations.ProviderAllocationsOpts{}, - ProjectID: *existing.ProjectID, - UserID: *existing.UserID, - ConsumerGeneration: existing.ConsumerGeneration, + Allocations: map[string]allocations.ProviderAllocationsOpts{ + resourceProvider.UUID: { + Resources: map[string]int{"VCPU": 1}, + }, + }, + ProjectID: "test-project", + UserID: "test-user", + ConsumerGeneration: nil, }).ExtractErr() th.AssertNoErr(t, err) + + // Act: Delete all allocations for the consumer. + err = allocations.Delete(context.TODO(), client, consumerUUID).ExtractErr() + th.AssertNoErr(t, err) + + // Assert: Consumer now returns an empty allocations map. + allocs, err := allocations.Get(context.TODO(), client, consumerUUID).Extract() + th.AssertNoErr(t, err) + th.AssertEquals(t, 0, len(allocs.Allocations)) +} + +func TestDeleteAllocationsNotFound(t *testing.T) { + clients.RequireAdmin(t) + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + resourceProvider, err := CreateResourceProvider(t, client) + th.AssertNoErr(t, err) + defer DeleteResourceProvider(t, client, resourceProvider.UUID) + + // Assert: An RP that was never a consumer returns 404 on DELETE. + err = allocations.Delete(context.TODO(), client, resourceProvider.UUID).ExtractErr() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } diff --git a/openstack/placement/v1/allocations/doc.go b/openstack/placement/v1/allocations/doc.go index 769c114258..83917d40c0 100644 --- a/openstack/placement/v1/allocations/doc.go +++ b/openstack/placement/v1/allocations/doc.go @@ -60,5 +60,16 @@ generation first and pass it in. if err != nil { panic(err) } + +# Example to delete all allocations for a consumer + +Note: using Update with an empty Allocations map is generally safer because +it is protected by the consumer generation check. Use Delete only when you +do not need that protection. + + err = allocations.Delete(context.TODO(), placementClient, consumerUUID).ExtractErr() + if err != nil { + panic(err) + } */ package allocations diff --git a/openstack/placement/v1/allocations/requests.go b/openstack/placement/v1/allocations/requests.go index 0996df58c1..6d65faeeb7 100644 --- a/openstack/placement/v1/allocations/requests.go +++ b/openstack/placement/v1/allocations/requests.go @@ -75,3 +75,15 @@ func Update(ctx context.Context, client *gophercloud.ServiceClient, consumerUUID _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return } + +// Delete removes all allocations for a consumer. Returns 204 on success or +// 404 if the consumer does not exist. +// +// Note: using Update with an empty Allocations map is generally safer because +// it is protected by the consumer generation check, preventing accidental +// deletion under concurrent updates. +func Delete(ctx context.Context, client *gophercloud.ServiceClient, consumerUUID string) (r DeleteResult) { + resp, err := client.Delete(ctx, deleteURL(client, consumerUUID), nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} diff --git a/openstack/placement/v1/allocations/results.go b/openstack/placement/v1/allocations/results.go index ce5775df81..e8c30bff7f 100644 --- a/openstack/placement/v1/allocations/results.go +++ b/openstack/placement/v1/allocations/results.go @@ -50,3 +50,9 @@ func (r GetResult) Extract() (*Allocations, error) { type UpdateResult struct { gophercloud.ErrResult } + +// DeleteResult is the result of a Delete operation. Call its ExtractErr +// method to determine if the request succeeded or failed. +type DeleteResult struct { + gophercloud.ErrResult +} diff --git a/openstack/placement/v1/allocations/testing/fixtures_test.go b/openstack/placement/v1/allocations/testing/fixtures_test.go index cc329aa2b1..3a5c4e19ad 100644 --- a/openstack/placement/v1/allocations/testing/fixtures_test.go +++ b/openstack/placement/v1/allocations/testing/fixtures_test.go @@ -13,6 +13,7 @@ import ( const ConsumerUUID = "ba8f2c8e-0bf7-4a32-aacf-7c11f7f9a321" const EmptyConsumerUUID = "00000000-0000-0000-0000-000000000000" const ConflictConsumerUUID = "ffffffff-ffff-ffff-ffff-ffffffffffff" +const NotFoundConsumerUUID = "11111111-1111-1111-1111-111111111111" const ProviderUUID1 = "7d4f1abe-2f91-4f7a-8872-b70d9fb5c3dd" const ProviderUUID2 = "f3f97e00-13e1-4c88-a7cd-db3bb4f99357" const ProjectID = "42a2b0fa980d4f7f873e8f0d8b4e1b0e" @@ -238,3 +239,38 @@ func HandleUpdateAllocationsConflict(t *testing.T, fakeServer th.FakeServer) { fmt.Fprint(w, `{"errors":[{"status":409,"title":"Conflict","code":"placement.concurrent_update"}]}`) }) } + +// HandleDeleteAndGetAllocationsSuccess handles DELETE followed by GET on the same URL. +// DELETE returns 204; the subsequent GET returns an empty allocations body. +func HandleDeleteAndGetAllocationsSuccess(t *testing.T, fakeServer th.FakeServer) { + url := fmt.Sprintf("/allocations/%s", ConsumerUUID) + + fakeServer.Mux.HandleFunc(url, func(w http.ResponseWriter, r *http.Request) { + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + switch r.Method { + case http.MethodDelete: + w.WriteHeader(http.StatusNoContent) + case http.MethodGet: + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + fmt.Fprint(w, GetEmptyAllocationsBody) + default: + t.Fatalf("unexpected method: %s", r.Method) + } + }) +} + +// HandleDeleteAllocationsNotFound simulates a 404 when the consumer does not exist. +func HandleDeleteAllocationsNotFound(t *testing.T, fakeServer th.FakeServer) { + url := fmt.Sprintf("/allocations/%s", NotFoundConsumerUUID) + + fakeServer.Mux.HandleFunc(url, func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "DELETE") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusNotFound) + fmt.Fprint(w, `{"errors":[{"status":404,"title":"Not Found","code":"placement.undefined_code"}]}`) + }) +} diff --git a/openstack/placement/v1/allocations/testing/requests_test.go b/openstack/placement/v1/allocations/testing/requests_test.go index 510fd78195..5ff5a6e4d6 100644 --- a/openstack/placement/v1/allocations/testing/requests_test.go +++ b/openstack/placement/v1/allocations/testing/requests_test.go @@ -99,3 +99,28 @@ func TestUpdateConflict(t *testing.T) { }).ExtractErr() th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusConflict)) } + +func TestDeleteSuccess(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleDeleteAndGetAllocationsSuccess(t, fakeServer) + + err := allocations.Delete(context.TODO(), client.ServiceClient(fakeServer), ConsumerUUID).ExtractErr() + th.AssertNoErr(t, err) + + // Assert: Consumer now has no allocations. + actual, err := allocations.Get(context.TODO(), client.ServiceClient(fakeServer), ConsumerUUID).Extract() + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedEmptyAllocations, *actual) +} + +func TestDeleteNotFound(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleDeleteAllocationsNotFound(t, fakeServer) + + err := allocations.Delete(context.TODO(), client.ServiceClient(fakeServer), NotFoundConsumerUUID).ExtractErr() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) +} diff --git a/openstack/placement/v1/allocations/urls.go b/openstack/placement/v1/allocations/urls.go index 93c43d3c66..525468caf3 100644 --- a/openstack/placement/v1/allocations/urls.go +++ b/openstack/placement/v1/allocations/urls.go @@ -9,3 +9,7 @@ func getURL(client *gophercloud.ServiceClient, consumerUUID string) string { func updateURL(client *gophercloud.ServiceClient, consumerUUID string) string { return client.ServiceURL("allocations", consumerUUID) } + +func deleteURL(client *gophercloud.ServiceClient, consumerUUID string) string { + return client.ServiceURL("allocations", consumerUUID) +} From ce2a0d51b0acfea0df58a2ccfd6374e572325629 Mon Sep 17 00:00:00 2001 From: Dominik Danelski Date: Fri, 10 Apr 2026 15:37:24 +0200 Subject: [PATCH 379/429] Implement Placement allocations POST Related #526 API reference: https://docs.openstack.org/api-ref/placement/?expanded=#manage-allocations Code reference: https://opendev.org/openstack/placement/src/branch/stable/2026.1/placement/handlers/allocation.py#L166-L205 --- .../placement/v1/allocations_test.go | 51 +++++++++ openstack/placement/v1/allocations/doc.go | 34 ++++++ .../placement/v1/allocations/requests.go | 48 +++++++++ openstack/placement/v1/allocations/results.go | 6 ++ .../v1/allocations/testing/fixtures_test.go | 101 ++++++++++++++++++ .../v1/allocations/testing/requests_test.go | 59 ++++++++++ openstack/placement/v1/allocations/urls.go | 4 + 7 files changed, 303 insertions(+) diff --git a/internal/acceptance/openstack/placement/v1/allocations_test.go b/internal/acceptance/openstack/placement/v1/allocations_test.go index 63716941e7..2a3607b219 100644 --- a/internal/acceptance/openstack/placement/v1/allocations_test.go +++ b/internal/acceptance/openstack/placement/v1/allocations_test.go @@ -216,3 +216,54 @@ func TestDeleteAllocationsNotFound(t *testing.T) { err = allocations.Delete(context.TODO(), client, resourceProvider.UUID).ExtractErr() th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } + +func TestManageAllocationsSuccess(t *testing.T) { + clients.RequireAdmin(t) + clients.SkipReleasesBelow(t, "stable/rocky") + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + resourceProvider, _, err := CreateResourceProviderWithVCPUInventory(t, client) + th.AssertNoErr(t, err) + defer DeleteResourceProvider(t, client, resourceProvider.UUID) + + consumer1UUID := fmt.Sprintf("%08x-0000-0000-0000-000000000004", rand.Int31()) + consumer2UUID := fmt.Sprintf("%08x-0000-0000-0000-000000000005", rand.Int31()) + defer allocations.Delete(context.TODO(), client, consumer1UUID) + defer allocations.Delete(context.TODO(), client, consumer2UUID) + + client.Microversion = "1.28" + + // Act: Atomically set allocations for two consumers. + err = allocations.Manage(context.TODO(), client, allocations.ManageOpts{ + consumer1UUID: { + Allocations: map[string]allocations.ProviderAllocationsOpts{ + resourceProvider.UUID: { + Resources: map[string]int{"VCPU": 1}, + }, + }, + ProjectID: "test-project", + UserID: "test-user", + ConsumerGeneration: nil, + }, + consumer2UUID: { + Allocations: map[string]allocations.ProviderAllocationsOpts{ + resourceProvider.UUID: { + Resources: map[string]int{"VCPU": 1}, + }, + }, + ProjectID: "test-project", + UserID: "test-user", + ConsumerGeneration: nil, + }, + }).ExtractErr() + th.AssertNoErr(t, err) + + for _, consumerUUID := range []string{consumer1UUID, consumer2UUID} { + allocs, err := allocations.Get(context.TODO(), client, consumerUUID).Extract() + th.AssertNoErr(t, err) + th.AssertEquals(t, 1, len(allocs.Allocations)) + th.AssertEquals(t, 1, allocs.Allocations[resourceProvider.UUID].Resources["VCPU"]) + } +} diff --git a/openstack/placement/v1/allocations/doc.go b/openstack/placement/v1/allocations/doc.go index 83917d40c0..8233418bb1 100644 --- a/openstack/placement/v1/allocations/doc.go +++ b/openstack/placement/v1/allocations/doc.go @@ -71,5 +71,39 @@ do not need that protection. if err != nil { panic(err) } + +# Example to atomically set allocations for multiple consumers (microversion 1.13+) + +Manage sets allocations for any number of consumers in a single atomic +request. The map key is the consumer UUID. Use microversion 1.28 or later +for generation-safe writes. + + placementClient.Microversion = "1.28" + + err = allocations.Manage(context.TODO(), placementClient, allocations.ManageOpts{ + consumer1UUID: { + Allocations: map[string]allocations.ProviderAllocationsOpts{ + providerUUID: { + Resources: map[string]int{"VCPU": 2}, + }, + }, + ProjectID: projectID, + UserID: userID, + ConsumerGeneration: nil, + }, + consumer2UUID: { + Allocations: map[string]allocations.ProviderAllocationsOpts{ + providerUUID: { + Resources: map[string]int{"VCPU": 1}, + }, + }, + ProjectID: projectID, + UserID: userID, + ConsumerGeneration: nil, + }, + }).ExtractErr() + if err != nil { + panic(err) + } */ package allocations diff --git a/openstack/placement/v1/allocations/requests.go b/openstack/placement/v1/allocations/requests.go index 6d65faeeb7..6640681f4c 100644 --- a/openstack/placement/v1/allocations/requests.go +++ b/openstack/placement/v1/allocations/requests.go @@ -2,6 +2,7 @@ package allocations import ( "context" + "encoding/json" "github.com/gophercloud/gophercloud/v2" ) @@ -87,3 +88,50 @@ func Delete(ctx context.Context, client *gophercloud.ServiceClient, consumerUUID _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return } + +// ManageOptsBuilder allows extensions to add additional parameters to the +// Manage request. +type ManageOptsBuilder interface { + ToAllocationManageMap() (map[string]any, error) +} + +// ManageOpts specifies allocations for multiple consumers in a single atomic +// operation. The map key is the consumer UUID; the value describes the +// allocations and consumer metadata for that consumer. +// +// This requires microversion 1.13 or later. For generation-safe writes, use +// microversion 1.28 or later and set ConsumerGeneration on each entry. +// +// Set ConsumerGeneration to nil for new consumers (serializes as JSON null). +// For existing consumers, set it to the generation returned by a prior Get +// call. A mismatch on any entry causes a 409 Conflict for the entire batch. +type ManageOpts map[string]UpdateOpts + +// ToAllocationManageMap constructs a request body from ManageOpts. +func (opts ManageOpts) ToAllocationManageMap() (map[string]any, error) { + b, err := json.Marshal(opts) + if err != nil { + return nil, err + } + var m map[string]any + err = json.Unmarshal(b, &m) + return m, err +} + +// Manage atomically sets allocations for one or more consumers in a single +// request. +// +// Requires microversion 1.13 or later. For generation-safe writes, use +// microversion 1.28 or later. +func Manage(ctx context.Context, client *gophercloud.ServiceClient, opts ManageOptsBuilder) (r ManageResult) { + b, err := opts.ToAllocationManageMap() + if err != nil { + r.Err = err + return + } + resp, err := client.Post(ctx, manageURL(client), b, nil, &gophercloud.RequestOpts{ + OkCodes: []int{204}, + }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} diff --git a/openstack/placement/v1/allocations/results.go b/openstack/placement/v1/allocations/results.go index e8c30bff7f..5ca69a8894 100644 --- a/openstack/placement/v1/allocations/results.go +++ b/openstack/placement/v1/allocations/results.go @@ -56,3 +56,9 @@ type UpdateResult struct { type DeleteResult struct { gophercloud.ErrResult } + +// ManageResult is the result of a Manage operation. Call its ExtractErr +// method to determine if the request succeeded or failed. +type ManageResult struct { + gophercloud.ErrResult +} diff --git a/openstack/placement/v1/allocations/testing/fixtures_test.go b/openstack/placement/v1/allocations/testing/fixtures_test.go index 3a5c4e19ad..5e75fd4a72 100644 --- a/openstack/placement/v1/allocations/testing/fixtures_test.go +++ b/openstack/placement/v1/allocations/testing/fixtures_test.go @@ -14,6 +14,8 @@ const ConsumerUUID = "ba8f2c8e-0bf7-4a32-aacf-7c11f7f9a321" const EmptyConsumerUUID = "00000000-0000-0000-0000-000000000000" const ConflictConsumerUUID = "ffffffff-ffff-ffff-ffff-ffffffffffff" const NotFoundConsumerUUID = "11111111-1111-1111-1111-111111111111" +const ManageConsumerUUID1 = "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" +const ManageConsumerUUID2 = "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb" const ProviderUUID1 = "7d4f1abe-2f91-4f7a-8872-b70d9fb5c3dd" const ProviderUUID2 = "f3f97e00-13e1-4c88-a7cd-db3bb4f99357" const ProjectID = "42a2b0fa980d4f7f873e8f0d8b4e1b0e" @@ -149,6 +151,65 @@ var ExpectedAllocationsAfterUpdate = allocations.Allocations{ ConsumerGeneration: &consumerGenerationAfterUpdate, } +var ManageAllocationsRequest = fmt.Sprintf(` +{ + "%s": { + "allocations": { + "%s": { + "resources": { + "VCPU": 1 + } + } + }, + "project_id": "%s", + "user_id": "%s", + "consumer_generation": null + }, + "%s": { + "allocations": { + "%s": { + "resources": { + "VCPU": 1 + } + } + }, + "project_id": "%s", + "user_id": "%s", + "consumer_generation": null + } +} +`, ManageConsumerUUID1, ProviderUUID1, ProjectID, UserID, ManageConsumerUUID2, ProviderUUID1, ProjectID, UserID) + +var GetAllocationsAfterManageBody = fmt.Sprintf(` +{ + "allocations": { + "%s": { + "generation": 1, + "resources": { + "VCPU": 1 + } + } + }, + "project_id": "%s", + "user_id": "%s", + "consumer_generation": 1 +} +`, ProviderUUID1, ProjectID, UserID) + +var ExpectedAllocationsAfterManage = allocations.Allocations{ + Allocations: map[string]allocations.ProviderAllocations{ + ProviderUUID1: { + Generation: 1, + Resources: map[string]int{ + "VCPU": 1, + }, + }, + }, + ProjectID: &projectID, + UserID: &userID, + ConsumerGeneration: &consumerGenerationAfterUpdate, +} + func HandleGetAllocationsSuccess(t *testing.T, fakeServer th.FakeServer) { url := fmt.Sprintf("/allocations/%s", ConsumerUUID) @@ -274,3 +335,43 @@ func HandleDeleteAllocationsNotFound(t *testing.T, fakeServer th.FakeServer) { fmt.Fprint(w, `{"errors":[{"status":404,"title":"Not Found","code":"placement.undefined_code"}]}`) }) } + +// HandleManageAllocationsSuccess handles POST to /allocations, verifying the +// request body, then handles GET requests for each managed consumer. +func HandleManageAllocationsSuccess(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/allocations", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestJSONRequest(t, r, ManageAllocationsRequest) + + w.WriteHeader(http.StatusNoContent) + }) + + for _, uuid := range []string{ManageConsumerUUID1, ManageConsumerUUID2} { + uuid := uuid + url := fmt.Sprintf("/allocations/%s", uuid) + fakeServer.Mux.HandleFunc(url, func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + fmt.Fprint(w, GetAllocationsAfterManageBody) + }) + } +} + +// HandleManageAllocationsConflict simulates a 409 when a consumer_generation +// in the batch does not match the server's current value. +func HandleManageAllocationsConflict(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/allocations", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusConflict) + fmt.Fprint(w, `{"errors":[{"status":409,"title":"Conflict","code":"placement.concurrent_update"}]}`) + }) +} diff --git a/openstack/placement/v1/allocations/testing/requests_test.go b/openstack/placement/v1/allocations/testing/requests_test.go index 5ff5a6e4d6..ac259167f9 100644 --- a/openstack/placement/v1/allocations/testing/requests_test.go +++ b/openstack/placement/v1/allocations/testing/requests_test.go @@ -124,3 +124,62 @@ func TestDeleteNotFound(t *testing.T) { err := allocations.Delete(context.TODO(), client.ServiceClient(fakeServer), NotFoundConsumerUUID).ExtractErr() th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } + +func TestManageSuccess(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleManageAllocationsSuccess(t, fakeServer) + + err := allocations.Manage(context.TODO(), client.ServiceClient(fakeServer), allocations.ManageOpts{ + ManageConsumerUUID1: { + Allocations: map[string]allocations.ProviderAllocationsOpts{ + ProviderUUID1: { + Resources: map[string]int{"VCPU": 1}, + }, + }, + ProjectID: ProjectID, + UserID: UserID, + ConsumerGeneration: nil, + }, + ManageConsumerUUID2: { + Allocations: map[string]allocations.ProviderAllocationsOpts{ + ProviderUUID1: { + Resources: map[string]int{"VCPU": 1}, + }, + }, + ProjectID: ProjectID, + UserID: UserID, + ConsumerGeneration: nil, + }, + }).ExtractErr() + th.AssertNoErr(t, err) + + for _, uuid := range []string{ManageConsumerUUID1, ManageConsumerUUID2} { + actual, err := allocations.Get(context.TODO(), client.ServiceClient(fakeServer), uuid).Extract() + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedAllocationsAfterManage, *actual) + } +} + +func TestManageConflict(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleManageAllocationsConflict(t, fakeServer) + + staleGeneration := 0 + err := allocations.Manage(context.TODO(), client.ServiceClient(fakeServer), allocations.ManageOpts{ + ConflictConsumerUUID: { + Allocations: map[string]allocations.ProviderAllocationsOpts{ + ProviderUUID1: { + Resources: map[string]int{"VCPU": 1}, + }, + }, + ProjectID: ProjectID, + UserID: UserID, + ConsumerGeneration: &staleGeneration, + }, + }).ExtractErr() + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusConflict)) +} diff --git a/openstack/placement/v1/allocations/urls.go b/openstack/placement/v1/allocations/urls.go index 525468caf3..267adb143b 100644 --- a/openstack/placement/v1/allocations/urls.go +++ b/openstack/placement/v1/allocations/urls.go @@ -13,3 +13,7 @@ func updateURL(client *gophercloud.ServiceClient, consumerUUID string) string { func deleteURL(client *gophercloud.ServiceClient, consumerUUID string) string { return client.ServiceURL("allocations", consumerUUID) } + +func manageURL(client *gophercloud.ServiceClient) string { + return client.ServiceURL("allocations") +} From 5f3ae481e5e4ae57da8cfbcbfcfdb7aa8a347964 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 09:17:52 +0000 Subject: [PATCH 380/429] build(deps): bump golang.org/x/crypto from 0.49.0 to 0.50.0 Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.49.0 to 0.50.0. - [Commits](https://github.com/golang/crypto/compare/v0.49.0...v0.50.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-version: 0.50.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 2c668ddd43..37b304d220 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.25.0 require ( go.yaml.in/yaml/v3 v3.0.4 - golang.org/x/crypto v0.49.0 + golang.org/x/crypto v0.50.0 ) -require golang.org/x/sys v0.42.0 // indirect +require golang.org/x/sys v0.43.0 // indirect diff --git a/go.sum b/go.sum index 53ebe91e84..7086387134 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,10 @@ go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= -golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= -golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= -golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU= -golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A= +golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= +golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q= +golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= +golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY= +golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 8d50d8848bca4805b30388ce03fc452b069569d4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 09:19:18 +0000 Subject: [PATCH 381/429] build(deps): bump actions/upload-artifact from 7.0.0 to 7.0.1 Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 7.0.0 to 7.0.1. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/bbbca2ddaa5d8feaa63e36b76fdaad77386f024f...043fb46d1a93c77aae656e7c1c64a875d1fc6a0a) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: 7.0.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/functional-baremetal.yaml | 2 +- .github/workflows/functional-basic.yaml | 2 +- .github/workflows/functional-blockstorage.yaml | 2 +- .github/workflows/functional-compute.yaml | 2 +- .github/workflows/functional-containerinfra.yaml | 2 +- .github/workflows/functional-dns.yaml | 2 +- .github/workflows/functional-fwaas_v2.yaml | 2 +- .github/workflows/functional-identity.yaml | 2 +- .github/workflows/functional-image.yaml | 2 +- .github/workflows/functional-keymanager.yaml | 2 +- .github/workflows/functional-loadbalancer.yaml | 2 +- .github/workflows/functional-messaging.yaml | 2 +- .github/workflows/functional-metric.yaml | 2 +- .github/workflows/functional-networking.yaml | 2 +- .github/workflows/functional-objectstorage.yaml | 2 +- .github/workflows/functional-orchestration.yaml | 2 +- .github/workflows/functional-placement.yaml | 2 +- .github/workflows/functional-sharedfilesystems.yaml | 2 +- .github/workflows/functional-workflow.yaml | 2 +- .github/workflows/semver.yaml | 2 +- 20 files changed, 20 insertions(+), 20 deletions(-) diff --git a/.github/workflows/functional-baremetal.yaml b/.github/workflows/functional-baremetal.yaml index e7f0417392..5b2b84d9d1 100644 --- a/.github/workflows/functional-baremetal.yaml +++ b/.github/workflows/functional-baremetal.yaml @@ -120,7 +120,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: functional-baremetal-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-basic.yaml b/.github/workflows/functional-basic.yaml index ebde821546..4f19727a8e 100644 --- a/.github/workflows/functional-basic.yaml +++ b/.github/workflows/functional-basic.yaml @@ -76,7 +76,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: functional-basic-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-blockstorage.yaml b/.github/workflows/functional-blockstorage.yaml index 5df7932e68..7e0ba900dd 100644 --- a/.github/workflows/functional-blockstorage.yaml +++ b/.github/workflows/functional-blockstorage.yaml @@ -82,7 +82,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: functional-blockstorage-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-compute.yaml b/.github/workflows/functional-compute.yaml index 6f0a96a964..481ff8199f 100644 --- a/.github/workflows/functional-compute.yaml +++ b/.github/workflows/functional-compute.yaml @@ -82,7 +82,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: functional-compute-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-containerinfra.yaml b/.github/workflows/functional-containerinfra.yaml index eb0d408214..f429102f07 100644 --- a/.github/workflows/functional-containerinfra.yaml +++ b/.github/workflows/functional-containerinfra.yaml @@ -97,7 +97,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: functional-containerinfra-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-dns.yaml b/.github/workflows/functional-dns.yaml index 1ab0e95f4f..dc13f66fa5 100644 --- a/.github/workflows/functional-dns.yaml +++ b/.github/workflows/functional-dns.yaml @@ -84,7 +84,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: functional-dns-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-fwaas_v2.yaml b/.github/workflows/functional-fwaas_v2.yaml index 8e1d86203f..0868b67daf 100644 --- a/.github/workflows/functional-fwaas_v2.yaml +++ b/.github/workflows/functional-fwaas_v2.yaml @@ -105,7 +105,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: functional-fwaas_v2-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-identity.yaml b/.github/workflows/functional-identity.yaml index a986d9df3e..3bb9d7ac46 100644 --- a/.github/workflows/functional-identity.yaml +++ b/.github/workflows/functional-identity.yaml @@ -80,7 +80,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: functional-identity-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-image.yaml b/.github/workflows/functional-image.yaml index 4400ec1925..3fc2c83562 100644 --- a/.github/workflows/functional-image.yaml +++ b/.github/workflows/functional-image.yaml @@ -80,7 +80,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: functional-image-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-keymanager.yaml b/.github/workflows/functional-keymanager.yaml index 7bb4cdc1d9..5d7ebd3d6c 100644 --- a/.github/workflows/functional-keymanager.yaml +++ b/.github/workflows/functional-keymanager.yaml @@ -84,7 +84,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: functional-keymanager-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-loadbalancer.yaml b/.github/workflows/functional-loadbalancer.yaml index 588bc400f8..52dc11662e 100644 --- a/.github/workflows/functional-loadbalancer.yaml +++ b/.github/workflows/functional-loadbalancer.yaml @@ -94,7 +94,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: functional-loadbalancer-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-messaging.yaml b/.github/workflows/functional-messaging.yaml index 143a84c466..38a350e451 100644 --- a/.github/workflows/functional-messaging.yaml +++ b/.github/workflows/functional-messaging.yaml @@ -83,7 +83,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: functional-messaging-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-metric.yaml b/.github/workflows/functional-metric.yaml index b00719e921..387b9e06d0 100644 --- a/.github/workflows/functional-metric.yaml +++ b/.github/workflows/functional-metric.yaml @@ -83,7 +83,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: functional-metric-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-networking.yaml b/.github/workflows/functional-networking.yaml index b68e0f8788..85d71c51f8 100644 --- a/.github/workflows/functional-networking.yaml +++ b/.github/workflows/functional-networking.yaml @@ -100,7 +100,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: functional-networking-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-objectstorage.yaml b/.github/workflows/functional-objectstorage.yaml index 14a574cdba..92c2e9ee3a 100644 --- a/.github/workflows/functional-objectstorage.yaml +++ b/.github/workflows/functional-objectstorage.yaml @@ -86,7 +86,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: functional-objectstorage-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-orchestration.yaml b/.github/workflows/functional-orchestration.yaml index 72e7791674..d4a189f2bd 100644 --- a/.github/workflows/functional-orchestration.yaml +++ b/.github/workflows/functional-orchestration.yaml @@ -82,7 +82,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: functional-orchestration-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-placement.yaml b/.github/workflows/functional-placement.yaml index ef8fb9e3da..93c642a112 100644 --- a/.github/workflows/functional-placement.yaml +++ b/.github/workflows/functional-placement.yaml @@ -80,7 +80,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: functional-placement-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-sharedfilesystems.yaml b/.github/workflows/functional-sharedfilesystems.yaml index fd1fa1ec22..caf5aa09f9 100644 --- a/.github/workflows/functional-sharedfilesystems.yaml +++ b/.github/workflows/functional-sharedfilesystems.yaml @@ -98,7 +98,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: functional-sharedfilesystems-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/functional-workflow.yaml b/.github/workflows/functional-workflow.yaml index faa216b566..e78aec2438 100644 --- a/.github/workflows/functional-workflow.yaml +++ b/.github/workflows/functional-workflow.yaml @@ -85,7 +85,7 @@ jobs: - name: Upload logs artifacts on failure if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: functional-workflow-${{ matrix.name }}-${{ github.run_id }} path: /tmp/devstack-logs/* diff --git a/.github/workflows/semver.yaml b/.github/workflows/semver.yaml index 9e7133b525..67e0b7889c 100644 --- a/.github/workflows/semver.yaml +++ b/.github/workflows/semver.yaml @@ -60,7 +60,7 @@ jobs: - name: Upload semver results if: always() - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: semver-results path: semver-results/ From fe4fef20c1311950dd057873c2e5eebecbd335c5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2026 10:38:50 +0000 Subject: [PATCH 382/429] build(deps): bump zizmorcore/zizmor-action from 0.5.2 to 0.5.3 Bumps [zizmorcore/zizmor-action](https://github.com/zizmorcore/zizmor-action) from 0.5.2 to 0.5.3. - [Release notes](https://github.com/zizmorcore/zizmor-action/releases) - [Commits](https://github.com/zizmorcore/zizmor-action/compare/71321a20a9ded102f6e9ce5718a2fcec2c4f70d8...b1d7e1fb5de872772f31590499237e7cce841e8e) --- updated-dependencies: - dependency-name: zizmorcore/zizmor-action dependency-version: 0.5.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/zizmor.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/zizmor.yaml b/.github/workflows/zizmor.yaml index 0a0fb0f41a..d07c30355a 100644 --- a/.github/workflows/zizmor.yaml +++ b/.github/workflows/zizmor.yaml @@ -25,4 +25,4 @@ jobs: persist-credentials: false - name: Run zizmor - uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2 + uses: zizmorcore/zizmor-action@b1d7e1fb5de872772f31590499237e7cce841e8e # v0.5.3 From 68af9d2dde7eacfecd560073a6b18047d01da73c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Apr 2026 09:20:33 +0000 Subject: [PATCH 383/429] build(deps): bump github/codeql-action from 4.35.1 to 4.35.2 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.35.1 to 4.35.2. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/c10b8064de6f491fea524254123dbe5e09572f13...95e58e9a2cdfd71adc6e0353d5c52f41a045d225) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 4.35.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql-analysis.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yaml b/.github/workflows/codeql-analysis.yaml index a445b45fc9..813e1e3034 100644 --- a/.github/workflows/codeql-analysis.yaml +++ b/.github/workflows/codeql-analysis.yaml @@ -29,12 +29,12 @@ jobs: cache: true - name: Initialize CodeQL - uses: github/codeql-action/init@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1 + uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1 + uses: github/codeql-action/autobuild@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1 + uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 From a95f7c37f9449833e705bc74e8fceccbeb3724c7 Mon Sep 17 00:00:00 2001 From: Winicius Silva Date: Thu, 23 Apr 2026 18:11:04 +0100 Subject: [PATCH 384/429] add a check to skip unmarshal for non-struct types --- results.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/results.go b/results.go index d5b947b7f0..101a7d24dc 100644 --- a/results.go +++ b/results.go @@ -117,6 +117,9 @@ func (r Result) extractIntoPtr(to any, label string) error { // a struct that is never used, but it's good enough to // trigger the UnmarshalJSON method. for i := 0; i < newType.NumField(); i++ { + if newType.Field(i).Kind() != reflect.Struct { + continue + } s := newType.Field(i).Addr().Interface() // Unmarshal is used rather than NewDecoder to also work From 81747255aa73752200eab67fd8344e665a8ba0fe Mon Sep 17 00:00:00 2001 From: Dominik Danelski Date: Mon, 4 May 2026 11:53:29 +0200 Subject: [PATCH 385/429] Use RandomUUID() for creating consumer IDs in Placement allocations Signed-off-by: Dominik Danelski --- .../openstack/placement/v1/allocations_test.go | 16 +++++++--------- internal/acceptance/tools/tools.go | 5 +++++ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/internal/acceptance/openstack/placement/v1/allocations_test.go b/internal/acceptance/openstack/placement/v1/allocations_test.go index 2a3607b219..bf95d0bc40 100644 --- a/internal/acceptance/openstack/placement/v1/allocations_test.go +++ b/internal/acceptance/openstack/placement/v1/allocations_test.go @@ -4,8 +4,6 @@ package v1 import ( "context" - "fmt" - "math/rand" "net/http" "testing" @@ -22,7 +20,7 @@ func TestGetAllocationsSuccess(t *testing.T) { client, err := clients.NewPlacementV1Client() th.AssertNoErr(t, err) - consumerUUID := fmt.Sprintf("%08x-0000-0000-0000-000000000000", rand.Int31()) + consumerUUID := tools.RandomUUID() // Assert: We don't have any allocations for this random UUID. // We get an empty allocations map, not 404. @@ -42,7 +40,7 @@ func TestUpdateAllocationsNewConsumerSuccess(t *testing.T) { th.AssertNoErr(t, err) defer DeleteResourceProvider(t, client, resourceProvider.UUID) - consumerUUID := fmt.Sprintf("%08x-0000-0000-0000-000000000000", rand.Int31()) + consumerUUID := tools.RandomUUID() defer allocations.Delete(context.TODO(), client, consumerUUID) client.Microversion = "1.28" @@ -78,7 +76,7 @@ func TestUpdateAllocationsSuccess(t *testing.T) { th.AssertNoErr(t, err) defer DeleteResourceProvider(t, client, resourceProvider.UUID) - consumerUUID := fmt.Sprintf("%08x-0000-0000-0000-000000000001", rand.Int31()) + consumerUUID := tools.RandomUUID() defer allocations.Delete(context.TODO(), client, consumerUUID) client.Microversion = "1.28" @@ -131,7 +129,7 @@ func TestUpdateAllocationsConflict(t *testing.T) { th.AssertNoErr(t, err) defer DeleteResourceProvider(t, client, resourceProvider.UUID) - consumerUUID := fmt.Sprintf("%08x-0000-0000-0000-000000000002", rand.Int31()) + consumerUUID := tools.RandomUUID() defer allocations.Delete(context.TODO(), client, consumerUUID) client.Microversion = "1.28" @@ -175,7 +173,7 @@ func TestDeleteAllocationsSuccess(t *testing.T) { th.AssertNoErr(t, err) defer DeleteResourceProvider(t, client, resourceProvider.UUID) - consumerUUID := fmt.Sprintf("%08x-0000-0000-0000-000000000003", rand.Int31()) + consumerUUID := tools.RandomUUID() client.Microversion = "1.28" @@ -228,8 +226,8 @@ func TestManageAllocationsSuccess(t *testing.T) { th.AssertNoErr(t, err) defer DeleteResourceProvider(t, client, resourceProvider.UUID) - consumer1UUID := fmt.Sprintf("%08x-0000-0000-0000-000000000004", rand.Int31()) - consumer2UUID := fmt.Sprintf("%08x-0000-0000-0000-000000000005", rand.Int31()) + consumer1UUID := tools.RandomUUID() + consumer2UUID := tools.RandomUUID() defer allocations.Delete(context.TODO(), client, consumer1UUID) defer allocations.Delete(context.TODO(), client, consumer2UUID) diff --git a/internal/acceptance/tools/tools.go b/internal/acceptance/tools/tools.go index 75ac004473..2f0238226a 100644 --- a/internal/acceptance/tools/tools.go +++ b/internal/acceptance/tools/tools.go @@ -3,6 +3,7 @@ package tools import ( "context" "encoding/json" + "fmt" "math/rand" "strings" "testing" @@ -69,6 +70,10 @@ func RandomInt(min, max int) int { return rand.Intn(max-min) + min } +func RandomUUID() string { + return fmt.Sprintf("%08x-0000-0000-0000-000000000000", rand.Int31()) +} + // Elide returns the first bit of its input string with a suffix of "..." if it's longer than // a comfortable 40 characters. func Elide(value string) string { From f1f4c79b15c77f6ecac7d03c892dbfea84ff3ae6 Mon Sep 17 00:00:00 2001 From: Dominik Danelski Date: Wed, 15 Apr 2026 15:53:11 +0200 Subject: [PATCH 386/429] Implement Placement usages Related #526 API reference: https://docs.openstack.org/api-ref/placement/?expanded=#list-usages Code reference: https://opendev.org/openstack/placement/src/branch/stable/2026.1/placement/handlers/usage.py#L83-L143 Signed-off-by: Dominik Danelski --- .../openstack/placement/v1/usages_test.go | 195 ++++++++++++++++++ openstack/placement/v1/usages/doc.go | 49 +++++ .../placement/v1/usages/microversions.go | 16 ++ openstack/placement/v1/usages/requests.go | 59 ++++++ openstack/placement/v1/usages/results.go | 33 +++ openstack/placement/v1/usages/testing/doc.go | 2 + .../v1/usages/testing/fixtures_test.go | 172 +++++++++++++++ .../v1/usages/testing/requests_test.go | 90 ++++++++ openstack/placement/v1/usages/urls.go | 7 + 9 files changed, 623 insertions(+) create mode 100644 internal/acceptance/openstack/placement/v1/usages_test.go create mode 100644 openstack/placement/v1/usages/doc.go create mode 100644 openstack/placement/v1/usages/microversions.go create mode 100644 openstack/placement/v1/usages/requests.go create mode 100644 openstack/placement/v1/usages/results.go create mode 100644 openstack/placement/v1/usages/testing/doc.go create mode 100644 openstack/placement/v1/usages/testing/fixtures_test.go create mode 100644 openstack/placement/v1/usages/testing/requests_test.go create mode 100644 openstack/placement/v1/usages/urls.go diff --git a/internal/acceptance/openstack/placement/v1/usages_test.go b/internal/acceptance/openstack/placement/v1/usages_test.go new file mode 100644 index 0000000000..20fa216a71 --- /dev/null +++ b/internal/acceptance/openstack/placement/v1/usages_test.go @@ -0,0 +1,195 @@ +//go:build acceptance || placement || usages + +package v1 + +import ( + "context" + "testing" + + "github.com/gophercloud/gophercloud/v2/internal/acceptance/clients" + "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" + "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/allocations" + "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/usages" + th "github.com/gophercloud/gophercloud/v2/testhelper" +) + +func TestGetUsagesSuccess(t *testing.T) { + clients.RequireAdmin(t) + clients.SkipReleasesBelow(t, "stable/rocky") + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + resourceProvider, _, err := CreateResourceProviderWithVCPUInventory(t, client) + th.AssertNoErr(t, err) + defer DeleteResourceProvider(t, client, resourceProvider.UUID) + + consumerUUID := tools.RandomUUID() + defer allocations.Delete(context.TODO(), client, consumerUUID) + + projectID := "test-project" + userID := "test-user" + + client.Microversion = "1.38" + + // Arrange: Create allocations for a consumer under the test project. + err = allocations.Update(context.TODO(), client, consumerUUID, allocations.UpdateOpts{ + Allocations: map[string]allocations.ProviderAllocationsOpts{ + resourceProvider.UUID: { + Resources: map[string]int{"VCPU": 2, "MEMORY_MB": 1024}, + }, + }, + ProjectID: projectID, + UserID: userID, + ConsumerGeneration: nil, + ConsumerType: "INSTANCE", + }).ExtractErr() + th.AssertNoErr(t, err) + + // Act: Retrieve total usages for the project (1.38+, grouped by consumer type). + totalUsages, err := usages.Get(context.TODO(), client, usages.GetOpts{ + ProjectID: projectID, + }).Extract() + th.AssertNoErr(t, err) + + // Assert: Exactly one consumer type "INSTANCE" with our exact resource usage. + th.AssertEquals(t, 1, len(totalUsages.Usages)) + ctUsage := totalUsages.Usages["INSTANCE"] + th.AssertEquals(t, 2, ctUsage["VCPU"]) + th.AssertEquals(t, 1024, ctUsage["MEMORY_MB"]) + th.AssertEquals(t, 1, ctUsage["consumer_count"]) + + tools.PrintResource(t, totalUsages) +} + +func TestGetUsagesWithUserSuccess(t *testing.T) { + clients.RequireAdmin(t) + clients.SkipReleasesBelow(t, "stable/rocky") + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + resourceProvider, _, err := CreateResourceProviderWithVCPUInventory(t, client) + th.AssertNoErr(t, err) + defer DeleteResourceProvider(t, client, resourceProvider.UUID) + + consumerUUID := tools.RandomUUID() + defer allocations.Delete(context.TODO(), client, consumerUUID) + + projectID := "test-project" + userID := "test-user" + + client.Microversion = "1.38" + + // Arrange: Create allocations. + err = allocations.Update(context.TODO(), client, consumerUUID, allocations.UpdateOpts{ + Allocations: map[string]allocations.ProviderAllocationsOpts{ + resourceProvider.UUID: { + Resources: map[string]int{"VCPU": 1}, + }, + }, + ProjectID: projectID, + UserID: userID, + ConsumerGeneration: nil, + ConsumerType: "INSTANCE", + }).ExtractErr() + th.AssertNoErr(t, err) + + // Act: Retrieve usages filtered by project and user (1.38+). + totalUsages, err := usages.Get(context.TODO(), client, usages.GetOpts{ + ProjectID: projectID, + UserID: userID, + }).Extract() + th.AssertNoErr(t, err) + + // Assert: Exactly one consumer type "INSTANCE" with our exact VCPU usage. + th.AssertEquals(t, 1, len(totalUsages.Usages)) + ctUsage := totalUsages.Usages["INSTANCE"] + th.AssertEquals(t, 1, ctUsage["VCPU"]) + th.AssertEquals(t, 1, ctUsage["consumer_count"]) + + tools.PrintResource(t, totalUsages) +} + +func TestGetUsagesEmptySuccess(t *testing.T) { + clients.RequireAdmin(t) + clients.SkipReleasesBelow(t, "stable/rocky") + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + client.Microversion = "1.38" + + // Act: Query usages for a project with no allocations. + totalUsages, err := usages.Get(context.TODO(), client, usages.GetOpts{ + ProjectID: "nonexistent-project-with-no-allocations", + }).Extract() + th.AssertNoErr(t, err) + + // Assert: Empty usages map. + th.AssertEquals(t, 0, len(totalUsages.Usages)) +} + +func TestGetUsagesPre138Success(t *testing.T) { + clients.RequireAdmin(t) + clients.SkipReleasesBelow(t, "stable/rocky") + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + resourceProvider, _, err := CreateResourceProviderWithVCPUInventory(t, client) + th.AssertNoErr(t, err) + defer DeleteResourceProvider(t, client, resourceProvider.UUID) + + consumerUUID := tools.RandomUUID() + defer allocations.Delete(context.TODO(), client, consumerUUID) + + projectID := "test-project" + userID := "test-user" + + client.Microversion = "1.28" + + // Arrange: Create allocations for a consumer. + err = allocations.Update(context.TODO(), client, consumerUUID, allocations.UpdateOpts{ + Allocations: map[string]allocations.ProviderAllocationsOpts{ + resourceProvider.UUID: { + Resources: map[string]int{"VCPU": 2, "MEMORY_MB": 1024}, + }, + }, + ProjectID: projectID, + UserID: userID, + ConsumerGeneration: nil, + }).ExtractErr() + th.AssertNoErr(t, err) + + // Act: Retrieve total usages for the project (pre-1.38, flat map). + totalUsages, err := usages.Get(context.TODO(), client, usages.GetOpts{ + ProjectID: projectID, + }).ExtractPre138() + th.AssertNoErr(t, err) + + // Assert: Usages reflect the allocations we just created. + th.AssertEquals(t, 2, totalUsages.Usages["VCPU"]) + th.AssertEquals(t, 1024, totalUsages.Usages["MEMORY_MB"]) + + tools.PrintResource(t, totalUsages) +} + +func TestGetUsagesPre138EmptySuccess(t *testing.T) { + clients.RequireAdmin(t) + clients.SkipReleasesBelow(t, "stable/rocky") + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + client.Microversion = "1.9" + + // Act: Query usages for a project with no allocations (pre-1.38). + totalUsages, err := usages.Get(context.TODO(), client, usages.GetOpts{ + ProjectID: "nonexistent-project-with-no-allocations", + }).ExtractPre138() + th.AssertNoErr(t, err) + + // Assert: Empty usages map. + th.AssertEquals(t, 0, len(totalUsages.Usages)) +} diff --git a/openstack/placement/v1/usages/doc.go b/openstack/placement/v1/usages/doc.go new file mode 100644 index 0000000000..ea629113b4 --- /dev/null +++ b/openstack/placement/v1/usages/doc.go @@ -0,0 +1,49 @@ +/* +Package usages retrieves total resource usage from the OpenStack Placement service. + +Usage API requests are available starting from microversion 1.9. + +# Example to get total usages grouped by consumer type (microversion 1.38+) + + placementClient.Microversion = "1.38" + + totalUsages, err := usages.Get(context.TODO(), placementClient, usages.GetOpts{ + ProjectID: projectID, + }).Extract() + if err != nil { + panic(err) + } + + for consumerType, usage := range totalUsages.Usages { + fmt.Printf("%s: VCPU=%d, consumer_count=%d\n", + consumerType, usage["VCPU"], usage["consumer_count"]) + } + +# Example to get total usages without consumer type grouping (microversion 1.9–1.37) + + placementClient.Microversion = "1.9" + + totalUsages, err := usages.Get(context.TODO(), placementClient, usages.GetOpts{ + ProjectID: projectID, + }).ExtractPre138() + if err != nil { + panic(err) + } + + fmt.Printf("VCPU usage: %d\n", totalUsages.Usages["VCPU"]) + +# Example to get total usages for a specific project and user + + placementClient.Microversion = "1.38" + + totalUsages, err := usages.Get(context.TODO(), placementClient, usages.GetOpts{ + ProjectID: projectID, + UserID: userID, + }).Extract() + if err != nil { + panic(err) + } + + fmt.Printf("%+v\n", totalUsages) +*/ +package usages diff --git a/openstack/placement/v1/usages/microversions.go b/openstack/placement/v1/usages/microversions.go new file mode 100644 index 0000000000..0b83cb06a6 --- /dev/null +++ b/openstack/placement/v1/usages/microversions.go @@ -0,0 +1,16 @@ +package usages + +// UsagesPre138 represents the total resource consumption for a project for +// microversions 1.9 through 1.37. In these versions, usages are not grouped +// by consumer type. +type UsagesPre138 struct { + // Usages maps resource class names to the total integer amount consumed. + Usages map[string]int `json:"usages"` +} + +// ExtractPre138 interprets a GetResult as UsagesPre138 (microversions 1.9–1.37). +func (r GetResult) ExtractPre138() (*UsagesPre138, error) { + var s UsagesPre138 + err := r.ExtractInto(&s) + return &s, err +} diff --git a/openstack/placement/v1/usages/requests.go b/openstack/placement/v1/usages/requests.go new file mode 100644 index 0000000000..0deedf8096 --- /dev/null +++ b/openstack/placement/v1/usages/requests.go @@ -0,0 +1,59 @@ +package usages + +import ( + "context" + "net/http" + + "github.com/gophercloud/gophercloud/v2" +) + +// GetOptsBuilder allows extensions to add additional parameters to the +// Get request. +type GetOptsBuilder interface { + ToUsagesGetQuery() (string, error) +} + +// GetOpts specifies the query parameters for retrieving total usages. +// +// This requires microversion 1.9 or later. +type GetOpts struct { + // ProjectID is required: only usages for this project are returned. + ProjectID string `q:"project_id"` + + // UserID is optional: when set, only usages for this user within the + // project are returned. + UserID string `q:"user_id,omitempty"` + + // ConsumerType is optional: when set, results are filtered to this consumer type. + // Available from microversion 1.38. + ConsumerType string `q:"consumer_type,omitempty"` +} + +// ToUsagesGetQuery formats a GetOpts into a query string. +func (opts GetOpts) ToUsagesGetQuery() (string, error) { + q, err := gophercloud.BuildQueryString(opts) + if err != nil { + return "", err + } + return q.String(), nil +} + +// Get retrieves the total resource usages for a project (and optionally a user). +// +// Requires microversion 1.9 or later. +func Get(ctx context.Context, client *gophercloud.ServiceClient, opts GetOptsBuilder) (r GetResult) { + url := getURL(client) + if opts != nil { + query, err := opts.ToUsagesGetQuery() + if err != nil { + r.Err = err + return + } + url += query + } + resp, err := client.Get(ctx, url, &r.Body, &gophercloud.RequestOpts{ + OkCodes: []int{http.StatusOK}, + }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} diff --git a/openstack/placement/v1/usages/results.go b/openstack/placement/v1/usages/results.go new file mode 100644 index 0000000000..ad19fee31b --- /dev/null +++ b/openstack/placement/v1/usages/results.go @@ -0,0 +1,33 @@ +package usages + +import "github.com/gophercloud/gophercloud/v2" + +// ConsumerTypeUsage maps resource class names to the total integer amount +// consumed by consumers of a given type. The special key "consumer_count" +// holds the number of consumers of this type. +type ConsumerTypeUsage map[string]int + +// Usages represents the total resource consumption for a project, grouped by +// consumer type. This is the response shape for microversion 1.38 and later. +// +// Each key in the Usages map is a consumer type name (e.g. "INSTANCE"). +// The value is a ConsumerTypeUsage containing resource class totals and a +// consumer_count entry. +type Usages struct { + // Usages maps consumer type names to their aggregated resource usage. + Usages map[string]ConsumerTypeUsage `json:"usages"` +} + +// GetResult is the result of a Get operation. Call its Extract method +// to interpret it as Usages (microversion 1.38+), or ExtractPre138 for +// earlier microversions. +type GetResult struct { + gophercloud.Result +} + +// Extract interprets a GetResult as Usages (microversion 1.38+). +func (r GetResult) Extract() (*Usages, error) { + var s Usages + err := r.ExtractInto(&s) + return &s, err +} diff --git a/openstack/placement/v1/usages/testing/doc.go b/openstack/placement/v1/usages/testing/doc.go new file mode 100644 index 0000000000..ed99c1eafa --- /dev/null +++ b/openstack/placement/v1/usages/testing/doc.go @@ -0,0 +1,2 @@ +// usages unit tests. +package testing diff --git a/openstack/placement/v1/usages/testing/fixtures_test.go b/openstack/placement/v1/usages/testing/fixtures_test.go new file mode 100644 index 0000000000..a1f9de05d4 --- /dev/null +++ b/openstack/placement/v1/usages/testing/fixtures_test.go @@ -0,0 +1,172 @@ +package testing + +import ( + "fmt" + "net/http" + "testing" + + "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/usages" + th "github.com/gophercloud/gophercloud/v2/testhelper" + "github.com/gophercloud/gophercloud/v2/testhelper/client" +) + +const ProjectID = "42a2b0fa980d4f7f873e8f0d8b4e1b0e" +const UserID = "b29d880b2c114d5d9a55748b26b2e41e" + +var GetUsagesBody = ` +{ + "usages": { + "INSTANCE": { + "VCPU": 2, + "MEMORY_MB": 2048, + "consumer_count": 1 + } + } +} +` + +var ExpectedUsages = usages.Usages{ + Usages: map[string]usages.ConsumerTypeUsage{ + "INSTANCE": { + "VCPU": 2, + "MEMORY_MB": 2048, + "consumer_count": 1, + }, + }, +} + +var GetUsagesWithUserBody = ` +{ + "usages": { + "INSTANCE": { + "VCPU": 2, + "MEMORY_MB": 2048, + "consumer_count": 1 + } + } +} +` + +var GetEmptyUsagesBody = ` +{ + "usages": {} +} +` + +var ExpectedEmptyUsages = usages.Usages{ + Usages: map[string]usages.ConsumerTypeUsage{}, +} + +var GetUsagesPre138Body = ` +{ + "usages": { + "VCPU": 2, + "MEMORY_MB": 2048 + } +} +` + +var ExpectedUsagesPre138 = usages.UsagesPre138{ + Usages: map[string]int{ + "VCPU": 2, + "MEMORY_MB": 2048, + }, +} + +var GetEmptyUsagesPre138Body = ` +{ + "usages": {} +} +` + +var ExpectedEmptyUsagesPre138 = usages.UsagesPre138{ + Usages: map[string]int{}, +} + +func HandleGetUsagesSuccess(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/usages", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + th.AssertEquals(t, ProjectID, r.URL.Query().Get("project_id")) + th.AssertEquals(t, "", r.URL.Query().Get("user_id")) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, GetUsagesBody) + }) +} + +func HandleGetUsagesWithUserSuccess(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/usages", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + th.AssertEquals(t, ProjectID, r.URL.Query().Get("project_id")) + th.AssertEquals(t, UserID, r.URL.Query().Get("user_id")) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, GetUsagesWithUserBody) + }) +} + +func HandleGetEmptyUsagesSuccess(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/usages", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + th.AssertEquals(t, ProjectID, r.URL.Query().Get("project_id")) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, GetEmptyUsagesBody) + }) +} + +func HandleGetUsagesPre138Success(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/usages", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + th.AssertEquals(t, ProjectID, r.URL.Query().Get("project_id")) + th.AssertEquals(t, "", r.URL.Query().Get("user_id")) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, GetUsagesPre138Body) + }) +} + +func HandleGetUsagesPre138WithUserSuccess(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/usages", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + th.AssertEquals(t, ProjectID, r.URL.Query().Get("project_id")) + th.AssertEquals(t, UserID, r.URL.Query().Get("user_id")) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, GetUsagesPre138Body) + }) +} + +func HandleGetEmptyUsagesPre138Success(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/usages", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + th.AssertEquals(t, ProjectID, r.URL.Query().Get("project_id")) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, GetEmptyUsagesPre138Body) + }) +} diff --git a/openstack/placement/v1/usages/testing/requests_test.go b/openstack/placement/v1/usages/testing/requests_test.go new file mode 100644 index 0000000000..022a1b9999 --- /dev/null +++ b/openstack/placement/v1/usages/testing/requests_test.go @@ -0,0 +1,90 @@ +package testing + +import ( + "context" + "testing" + + "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/usages" + th "github.com/gophercloud/gophercloud/v2/testhelper" + "github.com/gophercloud/gophercloud/v2/testhelper/client" +) + +func TestGetSuccess(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleGetUsagesSuccess(t, fakeServer) + + actual, err := usages.Get(context.TODO(), client.ServiceClient(fakeServer), usages.GetOpts{ + ProjectID: ProjectID, + }).Extract() + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedUsages, *actual) +} + +func TestGetWithUserSuccess(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleGetUsagesWithUserSuccess(t, fakeServer) + + actual, err := usages.Get(context.TODO(), client.ServiceClient(fakeServer), usages.GetOpts{ + ProjectID: ProjectID, + UserID: UserID, + }).Extract() + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedUsages, *actual) +} + +func TestGetEmptySuccess(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleGetEmptyUsagesSuccess(t, fakeServer) + + actual, err := usages.Get(context.TODO(), client.ServiceClient(fakeServer), usages.GetOpts{ + ProjectID: ProjectID, + }).Extract() + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedEmptyUsages, *actual) +} + +func TestGetPre138Success(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleGetUsagesPre138Success(t, fakeServer) + + actual, err := usages.Get(context.TODO(), client.ServiceClient(fakeServer), usages.GetOpts{ + ProjectID: ProjectID, + }).ExtractPre138() + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedUsagesPre138, *actual) +} + +func TestGetPre138WithUserSuccess(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleGetUsagesPre138WithUserSuccess(t, fakeServer) + + actual, err := usages.Get(context.TODO(), client.ServiceClient(fakeServer), usages.GetOpts{ + ProjectID: ProjectID, + UserID: UserID, + }).ExtractPre138() + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedUsagesPre138, *actual) +} + +func TestGetPre138EmptySuccess(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleGetEmptyUsagesPre138Success(t, fakeServer) + + actual, err := usages.Get(context.TODO(), client.ServiceClient(fakeServer), usages.GetOpts{ + ProjectID: ProjectID, + }).ExtractPre138() + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedEmptyUsagesPre138, *actual) +} diff --git a/openstack/placement/v1/usages/urls.go b/openstack/placement/v1/usages/urls.go new file mode 100644 index 0000000000..5de8523797 --- /dev/null +++ b/openstack/placement/v1/usages/urls.go @@ -0,0 +1,7 @@ +package usages + +import "github.com/gophercloud/gophercloud/v2" + +func getURL(client *gophercloud.ServiceClient) string { + return client.ServiceURL("usages") +} From 97695968f1304d2d396c93e2be9b6efbab5731a8 Mon Sep 17 00:00:00 2001 From: Dominik Danelski Date: Mon, 4 May 2026 12:16:34 +0200 Subject: [PATCH 387/429] Leverage RandomUUID() in Placement resourceproviders tests Signed-off-by: Dominik Danelski --- .../placement/v1/resourceproviders_test.go | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/internal/acceptance/openstack/placement/v1/resourceproviders_test.go b/internal/acceptance/openstack/placement/v1/resourceproviders_test.go index 3babbf9006..4b2f70d819 100644 --- a/internal/acceptance/openstack/placement/v1/resourceproviders_test.go +++ b/internal/acceptance/openstack/placement/v1/resourceproviders_test.go @@ -17,7 +17,6 @@ import ( const InventoryResourceClass = "VCPU" const MissingInventoryResourceClass = "NO_SUCH_CLASS" -const NonExistentRPUUID = "00000000-0000-0000-0000-000000000000" func TestResourceProviderList(t *testing.T) { clients.RequireAdmin(t) @@ -248,7 +247,7 @@ func TestResourceProviderUpdateInventoryNotFound(t *testing.T) { }, } - _, err = resourceproviders.UpdateInventory(context.TODO(), client, NonExistentRPUUID, InventoryResourceClass, updateOpts).Extract() + _, err = resourceproviders.UpdateInventory(context.TODO(), client, tools.RandomUUID(), InventoryResourceClass, updateOpts).Extract() th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } @@ -413,7 +412,7 @@ func TestResourceProviderUpdateInventoriesNotFound(t *testing.T) { }, } - _, err = resourceproviders.UpdateInventories(context.TODO(), client, NonExistentRPUUID, updateOpts).Extract() + _, err = resourceproviders.UpdateInventories(context.TODO(), client, tools.RandomUUID(), updateOpts).Extract() th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } @@ -487,11 +486,11 @@ func TestResourceProviderAggregatesNotFound(t *testing.T) { th.AssertNoErr(t, err) client.Microversion = "1.19" - _, err = resourceproviders.GetAggregates(context.TODO(), client, "00000000-0000-0000-0000-000000000000").Extract() + _, err = resourceproviders.GetAggregates(context.TODO(), client, tools.RandomUUID()).Extract() th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) client.Microversion = "1.1" - _, err = resourceproviders.GetAggregates(context.TODO(), client, "00000000-0000-0000-0000-000000000000").Extract() + _, err = resourceproviders.GetAggregates(context.TODO(), client, tools.RandomUUID()).Extract() th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } @@ -515,8 +514,8 @@ func TestResourceProviderUpdateAggregates(t *testing.T) { updateOpts := resourceproviders.UpdateAggregatesOpts{ ResourceProviderGeneration: before.ResourceProviderGeneration, Aggregates: []string{ - "6d84f6f6-7736-40ff-84d2-7db47f18ea25", - "f11f14bc-6f17-4f0a-b7c2-44b3e685ccf4", + tools.RandomUUID(), + tools.RandomUUID(), }, } @@ -553,7 +552,7 @@ func TestResourceProviderUpdateAggregateMismatch(t *testing.T) { updateOpts := resourceproviders.UpdateAggregatesOpts{ ResourceProviderGeneration: &wrongGeneration, Aggregates: []string{ - "6d84f6f6-7736-40ff-84d2-7db47f18ea25", + tools.RandomUUID(), }, } @@ -576,8 +575,8 @@ func TestResourceProviderUpdateAggregatesPreGeneration(t *testing.T) { updateOpts := resourceproviders.UpdateAggregatesOpts{ Aggregates: []string{ - "6d84f6f6-7736-40ff-84d2-7db47f18ea25", - "f11f14bc-6f17-4f0a-b7c2-44b3e685ccf4", + tools.RandomUUID(), + tools.RandomUUID(), }, } @@ -612,8 +611,8 @@ func TestResourceProviderUpdateAggregatesPreGenerationWithGenerationSuccess(t *t updateOpts := resourceproviders.UpdateAggregatesOpts{ ResourceProviderGeneration: &gen, Aggregates: []string{ - "6d84f6f6-7736-40ff-84d2-7db47f18ea25", - "f11f14bc-6f17-4f0a-b7c2-44b3e685ccf4", + tools.RandomUUID(), + tools.RandomUUID(), }, } From 99193c89ad32557372bf06dc3d60e0edad01201d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A2=D1=80=D0=B5=D1=84=D0=B8=D0=BB=D0=BE=D0=B2=20=D0=90?= =?UTF-8?q?=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20=D0=90=D0=BD?= =?UTF-8?q?=D0=B4=D1=80=D0=B5=D0=B5=D0=B2=D0=B8=D1=87?= Date: Tue, 5 May 2026 15:03:41 +0500 Subject: [PATCH 388/429] db/instances: remove hardcoded 300GB size cap --- openstack/db/v1/instances/requests.go | 8 +++--- .../db/v1/instances/testing/requests_test.go | 26 +++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/openstack/db/v1/instances/requests.go b/openstack/db/v1/instances/requests.go index b4e946025f..fd9599f985 100644 --- a/openstack/db/v1/instances/requests.go +++ b/openstack/db/v1/instances/requests.go @@ -56,8 +56,8 @@ type CreateOpts struct { // Either the integer UUID (in string form) of the flavor, or its URI // reference as specified in the response from the List() call. Required. FlavorRef string - // Specifies the volume size in gigabytes (GB). The value must be between 1 - // and 300. Required. + // Specifies the volume size in gigabytes (GB). The value must be > 1. + // Required. Size int // Specifies the volume type. VolumeType string @@ -77,11 +77,11 @@ type CreateOpts struct { // ToInstanceCreateMap will render a JSON map. func (opts CreateOpts) ToInstanceCreateMap() (map[string]any, error) { - if opts.Size > 300 || opts.Size < 1 { + if opts.Size < 1 { err := gophercloud.ErrInvalidInput{} err.Argument = "instances.CreateOpts.Size" err.Value = opts.Size - err.Info = "Size (GB) must be between 1-300" + err.Info = "Size (GB) must be >= 1" return nil, err } diff --git a/openstack/db/v1/instances/testing/requests_test.go b/openstack/db/v1/instances/testing/requests_test.go index b7278bf8d4..8961bc1727 100644 --- a/openstack/db/v1/instances/testing/requests_test.go +++ b/openstack/db/v1/instances/testing/requests_test.go @@ -78,6 +78,32 @@ func TestCreateWithFault(t *testing.T) { th.AssertDeepEquals(t, &expectedInstanceWithFault, instance) } +func TestCreateOptsToInstanceCreateMapAllowsSizeAbove300(t *testing.T) { + opts := instances.CreateOpts{ + FlavorRef: "1", + Size: 301, + } + + body, err := opts.ToInstanceCreateMap() + th.AssertNoErr(t, err) + + instance := body["instance"].(map[string]any) + volume := instance["volume"].(map[string]any) + th.AssertEquals(t, 301, volume["size"]) +} + +func TestCreateOptsToInstanceCreateMapRejectsSizeBelow1(t *testing.T) { + opts := instances.CreateOpts{ + FlavorRef: "1", + Size: 0, + } + + _, err := opts.ToInstanceCreateMap() + if err == nil { + t.Fatalf("expected error for invalid size, got nil") + } +} + func TestInstanceList(t *testing.T) { fakeServer := th.SetupHTTP() defer fakeServer.Teardown() From 21ae90aec409b484bcbc6ff0bda150c120bddbdb Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Tue, 5 May 2026 12:41:48 +0100 Subject: [PATCH 389/429] trivial: Replace reflect.Ptr with reflect.Pointer The former is a deprecated alias for the latter. Signed-off-by: Stephen Finucane --- params.go | 34 +++++++++++++++++----------------- results.go | 6 +++--- testhelper/convenience.go | 2 +- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/params.go b/params.go index e282033683..ddb61b3d08 100644 --- a/params.go +++ b/params.go @@ -58,12 +58,12 @@ above. */ func BuildRequestBody(opts any, parent string) (map[string]any, error) { optsValue := reflect.ValueOf(opts) - if optsValue.Kind() == reflect.Ptr { + if optsValue.Kind() == reflect.Pointer { optsValue = optsValue.Elem() } optsType := reflect.TypeOf(opts) - if optsType.Kind() == reflect.Ptr { + if optsType.Kind() == reflect.Pointer { optsType = optsType.Elem() } @@ -104,7 +104,7 @@ func BuildRequestBody(opts any, parent string) (map[string]any, error) { if reflect.ValueOf(xorField.Interface()) == reflect.Zero(xorField.Type()) { xorFieldIsZero = true } else { - if xorField.Kind() == reflect.Ptr { + if xorField.Kind() == reflect.Pointer { xorField = xorField.Elem() } xorFieldIsZero = isZero(xorField) @@ -126,7 +126,7 @@ func BuildRequestBody(opts any, parent string) (map[string]any, error) { if reflect.ValueOf(orField.Interface()) == reflect.Zero(orField.Type()) { orFieldIsZero = true } else { - if orField.Kind() == reflect.Ptr { + if orField.Kind() == reflect.Pointer { orField = orField.Elem() } orFieldIsZero = isZero(orField) @@ -145,15 +145,15 @@ func BuildRequestBody(opts any, parent string) (map[string]any, error) { continue } - if v.Kind() == reflect.Slice || (v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Slice) { + if v.Kind() == reflect.Slice || (v.Kind() == reflect.Pointer && v.Elem().Kind() == reflect.Slice) { sliceValue := v - if sliceValue.Kind() == reflect.Ptr { + if sliceValue.Kind() == reflect.Pointer { sliceValue = sliceValue.Elem() } for i := 0; i < sliceValue.Len(); i++ { element := sliceValue.Index(i) - if element.Kind() == reflect.Struct || (element.Kind() == reflect.Ptr && element.Elem().Kind() == reflect.Struct) { + if element.Kind() == reflect.Struct || (element.Kind() == reflect.Pointer && element.Elem().Kind() == reflect.Struct) { _, err := BuildRequestBody(element.Interface(), "") if err != nil { return nil, err @@ -161,7 +161,7 @@ func BuildRequestBody(opts any, parent string) (map[string]any, error) { } } } - if v.Kind() == reflect.Struct || (v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct) { + if v.Kind() == reflect.Struct || (v.Kind() == reflect.Pointer && v.Elem().Kind() == reflect.Struct) { if zero { //fmt.Printf("value before change: %+v\n", optsValue.Field(i)) if jsonTag != "" { @@ -169,7 +169,7 @@ func BuildRequestBody(opts any, parent string) (map[string]any, error) { if len(jsonTagPieces) > 1 && jsonTagPieces[1] == "omitempty" { if v.CanSet() { if !v.IsNil() { - if v.Kind() == reflect.Ptr { + if v.Kind() == reflect.Pointer { v.Set(reflect.Zero(v.Type())) } } @@ -292,7 +292,7 @@ func MaybeInt(original int) *int { /* func isUnderlyingStructZero(v reflect.Value) bool { switch v.Kind() { - case reflect.Ptr: + case reflect.Pointer: return isUnderlyingStructZero(v.Elem()) default: return isZero(v) @@ -305,7 +305,7 @@ var t time.Time func isZero(v reflect.Value) bool { //fmt.Printf("\n\nchecking isZero for value: %+v\n", v) switch v.Kind() { - case reflect.Ptr: + case reflect.Pointer: if v.IsNil() { return true } @@ -365,12 +365,12 @@ Slice are handled in one of two ways: */ func BuildQueryString(opts any) (*url.URL, error) { optsValue := reflect.ValueOf(opts) - if optsValue.Kind() == reflect.Ptr { + if optsValue.Kind() == reflect.Pointer { optsValue = optsValue.Elem() } optsType := reflect.TypeOf(opts) - if optsType.Kind() == reflect.Ptr { + if optsType.Kind() == reflect.Pointer { optsType = optsType.Elem() } @@ -390,7 +390,7 @@ func BuildQueryString(opts any) (*url.URL, error) { if !isZero(v) { loop: switch v.Kind() { - case reflect.Ptr: + case reflect.Pointer: v = v.Elem() goto loop case reflect.String: @@ -471,12 +471,12 @@ booleans and string values are supported. */ func BuildHeaders(opts any) (map[string]string, error) { optsValue := reflect.ValueOf(opts) - if optsValue.Kind() == reflect.Ptr { + if optsValue.Kind() == reflect.Pointer { optsValue = optsValue.Elem() } optsType := reflect.TypeOf(opts) - if optsType.Kind() == reflect.Ptr { + if optsType.Kind() == reflect.Pointer { optsType = optsType.Elem() } @@ -493,7 +493,7 @@ func BuildHeaders(opts any) (map[string]string, error) { // if the field is set, add it to the slice of query pieces if !isZero(v) { - if v.Kind() == reflect.Ptr { + if v.Kind() == reflect.Pointer { v = v.Elem() } switch v.Kind() { diff --git a/results.go b/results.go index 101a7d24dc..3ca191683e 100644 --- a/results.go +++ b/results.go @@ -84,7 +84,7 @@ func (r Result) extractIntoPtr(to any, label string) error { } toValue := reflect.ValueOf(to) - if toValue.Kind() == reflect.Ptr { + if toValue.Kind() == reflect.Pointer { toValue = toValue.Elem() } @@ -192,7 +192,7 @@ func (r Result) ExtractIntoStructPtr(to any, label string) error { } t := reflect.TypeOf(to) - if k := t.Kind(); k != reflect.Ptr { + if k := t.Kind(); k != reflect.Pointer { return fmt.Errorf("expected pointer, got %v", k) } @@ -227,7 +227,7 @@ func (r Result) ExtractIntoSlicePtr(to any, label string) error { } t := reflect.TypeOf(to) - if k := t.Kind(); k != reflect.Ptr { + if k := t.Kind(); k != reflect.Pointer { return fmt.Errorf("expected pointer, got %v", k) } diff --git a/testhelper/convenience.go b/testhelper/convenience.go index 57fa558fd1..9c61d48cf5 100644 --- a/testhelper/convenience.go +++ b/testhelper/convenience.go @@ -142,7 +142,7 @@ func deepDiffEqual(expected, actual reflect.Value, visited map[visit]bool, path } deepDiffEqual(expected.Elem(), actual.Elem(), visited, path, logDifference) return - case reflect.Ptr: + case reflect.Pointer: deepDiffEqual(expected.Elem(), actual.Elem(), visited, path, logDifference) return case reflect.Struct: From 3e40fa5b60f2871ae53ba4a4649634f040a1ea89 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Tue, 5 May 2026 12:38:20 +0100 Subject: [PATCH 390/429] Bump golangci-lint Signed-off-by: Stephen Finucane --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6b9d043cf2..9041e0c4fd 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ undefine GOFLAGS -GOLANGCI_LINT_VERSION?=v2.5.0 +GOLANGCI_LINT_VERSION?=v2.12.1 GOTESTSUM_VERSION?=v1.13.0 GO_TEST?=go run gotest.tools/gotestsum@$(GOTESTSUM_VERSION) --format testname -- TIMEOUT := "60m" From 759b9e0232636e5df6a500e38f3f4df81ddd95c9 Mon Sep 17 00:00:00 2001 From: DDuckSCH21 <100148228+DDuckSCH21@users.noreply.github.com> Date: Fri, 8 May 2026 10:03:17 +0500 Subject: [PATCH 391/429] Update openstack/db/v1/instances/requests.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martin André --- openstack/db/v1/instances/requests.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openstack/db/v1/instances/requests.go b/openstack/db/v1/instances/requests.go index fd9599f985..7e66cb26c0 100644 --- a/openstack/db/v1/instances/requests.go +++ b/openstack/db/v1/instances/requests.go @@ -56,7 +56,7 @@ type CreateOpts struct { // Either the integer UUID (in string form) of the flavor, or its URI // reference as specified in the response from the List() call. Required. FlavorRef string - // Specifies the volume size in gigabytes (GB). The value must be > 1. + // Specifies the volume size in gigabytes (GB). The value must be >= 1. The upper limit is specific to each OpenStack environment. // Required. Size int // Specifies the volume type. From 5e758886c7a6c547f8f5dae327886e6ec3890a38 Mon Sep 17 00:00:00 2001 From: Dominik Danelski Date: Tue, 12 May 2026 14:04:07 +0200 Subject: [PATCH 392/429] Make fields in Placement inventory update optional Previously, the inventory update opts were incorrectly aliased to the return struct. This disallowed the SDK users to omit its values which is something API permits for all arguments but total. Signed-off-by: Dominik Danelski --- .../placement/v1/allocationcandidates_test.go | 13 +- .../openstack/placement/v1/placement.go | 23 ++-- .../placement/v1/resourceproviders_test.go | 116 ++++++++++-------- .../placement/v1/resourceproviders/doc.go | 36 ++++-- .../v1/resourceproviders/requests.go | 20 ++- .../testing/fixtures_test.go | 38 ++++++ .../testing/requests_test.go | 8 +- 7 files changed, 169 insertions(+), 85 deletions(-) diff --git a/internal/acceptance/openstack/placement/v1/allocationcandidates_test.go b/internal/acceptance/openstack/placement/v1/allocationcandidates_test.go index 38cc6dcc06..d3b70ca87d 100644 --- a/internal/acceptance/openstack/placement/v1/allocationcandidates_test.go +++ b/internal/acceptance/openstack/placement/v1/allocationcandidates_test.go @@ -9,6 +9,7 @@ import ( "github.com/gophercloud/gophercloud/v2/internal/acceptance/clients" "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" + "github.com/gophercloud/gophercloud/v2/internal/ptr" "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/allocationcandidates" "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/resourceproviders" th "github.com/gophercloud/gophercloud/v2/testhelper" @@ -32,13 +33,13 @@ func createRPWithVCPUInventory(t *testing.T, microversion string) (string, func( inventories, err = resourceproviders.UpdateInventories(context.TODO(), client, rp.UUID, resourceproviders.UpdateInventoriesOpts{ ResourceProviderGeneration: inventories.ResourceProviderGeneration, - Inventories: map[string]resourceproviders.Inventory{ + Inventories: map[string]resourceproviders.InventoryUpdateBase{ "VCPU": { - AllocationRatio: 1.0, - MaxUnit: 8, - MinUnit: 1, - Reserved: 0, - StepSize: 1, + AllocationRatio: ptr.To(float32(1.0)), + MaxUnit: ptr.To(8), + MinUnit: ptr.To(1), + Reserved: ptr.To(0), + StepSize: ptr.To(1), Total: 8, }, }, diff --git a/internal/acceptance/openstack/placement/v1/placement.go b/internal/acceptance/openstack/placement/v1/placement.go index 18c3304075..b0caba5f76 100644 --- a/internal/acceptance/openstack/placement/v1/placement.go +++ b/internal/acceptance/openstack/placement/v1/placement.go @@ -6,6 +6,7 @@ import ( "github.com/gophercloud/gophercloud/v2" "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" + "github.com/gophercloud/gophercloud/v2/internal/ptr" "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/resourceproviders" th "github.com/gophercloud/gophercloud/v2/testhelper" ) @@ -87,21 +88,21 @@ func CreateResourceProviderWithVCPUInventory(t *testing.T, client *gophercloud.S updatedInventories, err := resourceproviders.UpdateInventories(context.TODO(), client, resourceProvider.UUID, resourceproviders.UpdateInventoriesOpts{ ResourceProviderGeneration: inventories.ResourceProviderGeneration, - Inventories: map[string]resourceproviders.Inventory{ + Inventories: map[string]resourceproviders.InventoryUpdateBase{ "VCPU": { - AllocationRatio: 1.0, - MaxUnit: 8, - MinUnit: 1, - Reserved: 0, - StepSize: 1, + AllocationRatio: ptr.To(float32(1.0)), + MaxUnit: ptr.To(8), + MinUnit: ptr.To(1), + Reserved: ptr.To(0), + StepSize: ptr.To(1), Total: 8, }, "MEMORY_MB": { - AllocationRatio: 1.0, - MaxUnit: 8192, - MinUnit: 1, - Reserved: 0, - StepSize: 1, + AllocationRatio: ptr.To(float32(1.0)), + MaxUnit: ptr.To(8192), + MinUnit: ptr.To(1), + Reserved: ptr.To(0), + StepSize: ptr.To(1), Total: 8192, }, }, diff --git a/internal/acceptance/openstack/placement/v1/resourceproviders_test.go b/internal/acceptance/openstack/placement/v1/resourceproviders_test.go index 4b2f70d819..02e794ca38 100644 --- a/internal/acceptance/openstack/placement/v1/resourceproviders_test.go +++ b/internal/acceptance/openstack/placement/v1/resourceproviders_test.go @@ -11,6 +11,7 @@ import ( "github.com/gophercloud/gophercloud/v2" "github.com/gophercloud/gophercloud/v2/internal/acceptance/clients" "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" + "github.com/gophercloud/gophercloud/v2/internal/ptr" "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/resourceproviders" th "github.com/gophercloud/gophercloud/v2/testhelper" ) @@ -121,13 +122,13 @@ func TestResourceProviderInventory(t *testing.T) { seededInventories, err := resourceproviders.UpdateInventories(context.TODO(), client, resourceProvider.UUID, resourceproviders.UpdateInventoriesOpts{ ResourceProviderGeneration: inventories.ResourceProviderGeneration, - Inventories: map[string]resourceproviders.Inventory{ + Inventories: map[string]resourceproviders.InventoryUpdateBase{ InventoryResourceClass: { - AllocationRatio: 1.0, - MaxUnit: 4, - MinUnit: 1, - Reserved: 0, - StepSize: 1, + AllocationRatio: ptr.To(float32(1.0)), + MaxUnit: ptr.To(4), + MinUnit: ptr.To(1), + Reserved: ptr.To(0), + StepSize: ptr.To(1), Total: 4, }, }, @@ -155,13 +156,13 @@ func TestResourceProviderInventoryNotFound(t *testing.T) { _, err = resourceproviders.UpdateInventories(context.TODO(), client, resourceProvider.UUID, resourceproviders.UpdateInventoriesOpts{ ResourceProviderGeneration: inventories.ResourceProviderGeneration, - Inventories: map[string]resourceproviders.Inventory{ + Inventories: map[string]resourceproviders.InventoryUpdateBase{ InventoryResourceClass: { - AllocationRatio: 1.0, - MaxUnit: 4, - MinUnit: 1, - Reserved: 0, - StepSize: 1, + AllocationRatio: ptr.To(float32(1.0)), + MaxUnit: ptr.To(4), + MinUnit: ptr.To(1), + Reserved: ptr.To(0), + StepSize: ptr.To(1), Total: 4, }, }, @@ -189,14 +190,14 @@ func TestResourceProviderUpdateInventory(t *testing.T) { // Arrange: The resource class on this provider must exist first seedOpts := resourceproviders.UpdateInventoriesOpts{ ResourceProviderGeneration: inventories.ResourceProviderGeneration, - Inventories: map[string]resourceproviders.Inventory{ + Inventories: map[string]resourceproviders.InventoryUpdateBase{ InventoryResourceClass: { - AllocationRatio: 1.0, - MaxUnit: 4, - MinUnit: 1, - Reserved: 0, - StepSize: 1, - Total: 4, + AllocationRatio: ptr.To(float32(1.0)), + MaxUnit: ptr.To(4), + MinUnit: ptr.To(1), + // Skipping Reserved on purpose + StepSize: ptr.To(1), + Total: 4, }, }, } @@ -215,7 +216,13 @@ func TestResourceProviderUpdateInventory(t *testing.T) { updateOpts := resourceproviders.UpdateInventoryOpts{ ResourceProviderGeneration: seededInventories.ResourceProviderGeneration, - Inventory: expectedInventory, + InventoryUpdateBase: resourceproviders.InventoryUpdateBase{ + AllocationRatio: ptr.To(expectedInventory.AllocationRatio), + MaxUnit: ptr.To(expectedInventory.MaxUnit), + MinUnit: ptr.To(expectedInventory.MinUnit), + StepSize: ptr.To(expectedInventory.StepSize), + Total: expectedInventory.Total, + }, } _, err = resourceproviders.UpdateInventory(context.TODO(), client, resourceProvider.UUID, InventoryResourceClass, updateOpts).Extract() @@ -237,12 +244,12 @@ func TestResourceProviderUpdateInventoryNotFound(t *testing.T) { updateOpts := resourceproviders.UpdateInventoryOpts{ ResourceProviderGeneration: 0, - Inventory: resourceproviders.Inventory{ - AllocationRatio: 1.0, - MaxUnit: 1, - MinUnit: 1, - Reserved: 0, - StepSize: 1, + InventoryUpdateBase: resourceproviders.InventoryUpdateBase{ + AllocationRatio: ptr.To(float32(1.0)), + MaxUnit: ptr.To(1), + MinUnit: ptr.To(1), + Reserved: ptr.To(0), + StepSize: ptr.To(1), Total: 1, }, } @@ -267,13 +274,13 @@ func TestResourceProviderDeleteInventorySuccess(t *testing.T) { _, err = resourceproviders.UpdateInventories(context.TODO(), client, resourceProvider.UUID, resourceproviders.UpdateInventoriesOpts{ ResourceProviderGeneration: inventories.ResourceProviderGeneration, - Inventories: map[string]resourceproviders.Inventory{ + Inventories: map[string]resourceproviders.InventoryUpdateBase{ InventoryResourceClass: { - AllocationRatio: 1.0, - MaxUnit: 4, - MinUnit: 1, - Reserved: 0, - StepSize: 1, + AllocationRatio: ptr.To(float32(1.0)), + MaxUnit: ptr.To(4), + MinUnit: ptr.To(1), + Reserved: ptr.To(0), + StepSize: ptr.To(1), Total: 4, }, }, @@ -320,21 +327,21 @@ func TestResourceProviderDeleteInventoriesSuccess(t *testing.T) { _, err = resourceproviders.UpdateInventories(context.TODO(), client, resourceProvider.UUID, resourceproviders.UpdateInventoriesOpts{ ResourceProviderGeneration: inventories.ResourceProviderGeneration, - Inventories: map[string]resourceproviders.Inventory{ + Inventories: map[string]resourceproviders.InventoryUpdateBase{ InventoryResourceClass: { - AllocationRatio: 1.0, - MaxUnit: 4, - MinUnit: 1, - Reserved: 0, - StepSize: 1, + AllocationRatio: ptr.To(float32(1.0)), + MaxUnit: ptr.To(4), + MinUnit: ptr.To(1), + Reserved: ptr.To(0), + StepSize: ptr.To(1), Total: 4, }, "MEMORY_MB": { - AllocationRatio: 1.0, - MaxUnit: 1024, - MinUnit: 1, - Reserved: 0, - StepSize: 1, + AllocationRatio: ptr.To(float32(1.0)), + MaxUnit: ptr.To(1024), + MinUnit: ptr.To(1), + Reserved: ptr.To(0), + StepSize: ptr.To(1), Total: 1024, }, }, @@ -380,7 +387,16 @@ func TestResourceProviderUpdateInventories(t *testing.T) { updateOpts := resourceproviders.UpdateInventoriesOpts{ ResourceProviderGeneration: inventories.ResourceProviderGeneration, - Inventories: expectedInventories, + Inventories: map[string]resourceproviders.InventoryUpdateBase{ + "DISK_GB": { + AllocationRatio: ptr.To(float32(1.0)), + MaxUnit: ptr.To(100), + MinUnit: ptr.To(1), + Reserved: ptr.To(0), + StepSize: ptr.To(1), + Total: 100, + }, + }, } _, err = resourceproviders.UpdateInventories(context.TODO(), client, resourceProvider.UUID, updateOpts).Extract() @@ -400,13 +416,13 @@ func TestResourceProviderUpdateInventoriesNotFound(t *testing.T) { updateOpts := resourceproviders.UpdateInventoriesOpts{ ResourceProviderGeneration: 0, - Inventories: map[string]resourceproviders.Inventory{ + Inventories: map[string]resourceproviders.InventoryUpdateBase{ InventoryResourceClass: { - AllocationRatio: 1.0, - MaxUnit: 1, - MinUnit: 1, - Reserved: 0, - StepSize: 1, + AllocationRatio: ptr.To(float32(1.0)), + MaxUnit: ptr.To(1), + MinUnit: ptr.To(1), + Reserved: ptr.To(0), + StepSize: ptr.To(1), Total: 1, }, }, diff --git a/openstack/placement/v1/resourceproviders/doc.go b/openstack/placement/v1/resourceproviders/doc.go index d0a6caa515..edd431767b 100644 --- a/openstack/placement/v1/resourceproviders/doc.go +++ b/openstack/placement/v1/resourceproviders/doc.go @@ -89,16 +89,22 @@ Example to update (replace) all resource provider inventories panic(err) } + allocationRatio := float32(16.0) + maxUnit := 4 + minUnit := 1 + reserved := 0 + stepSize := 1 + updateInventoriesOpts := resourceproviders.UpdateInventoriesOpts{ ResourceProviderGeneration: inventories.ResourceProviderGeneration, - Inventories: map[string]resourceproviders.Inventory{ + Inventories: map[string]resourceproviders.InventoryUpdateBase{ "VCPU": { Total: 4, - Reserved: 0, - MinUnit: 1, - MaxUnit: 4, - StepSize: 1, - AllocationRatio: 16.0, + Reserved: &reserved, + MinUnit: &minUnit, + MaxUnit: &maxUnit, + StepSize: &stepSize, + AllocationRatio: &allocationRatio, }, }, } @@ -115,16 +121,22 @@ Example to update one existing resource provider inventory panic(err) } + allocationRatio := float32(16.0) + maxUnit := 4 + minUnit := 1 + reserved := 0 + stepSize := 1 + // UpdateInventory updates an existing resource class inventory. updateInventoryOpts := resourceproviders.UpdateInventoryOpts{ ResourceProviderGeneration: inventories.ResourceProviderGeneration, - Inventory: resourceproviders.Inventory{ + InventoryUpdateBase: resourceproviders.InventoryUpdateBase{ Total: 4, - Reserved: 0, - MinUnit: 1, - MaxUnit: 4, - StepSize: 1, - AllocationRatio: 16.0, + Reserved: &reserved, + MinUnit: &minUnit, + MaxUnit: &maxUnit, + StepSize: &stepSize, + AllocationRatio: &allocationRatio, }, } diff --git a/openstack/placement/v1/resourceproviders/requests.go b/openstack/placement/v1/resourceproviders/requests.go index aecc975060..c921c562e0 100644 --- a/openstack/placement/v1/resourceproviders/requests.go +++ b/openstack/placement/v1/resourceproviders/requests.go @@ -177,8 +177,21 @@ type UpdateInventoriesOptsBuilder interface { ToResourceProviderUpdateInventoriesMap() (map[string]any, error) } +// InventoryUpdateBase contains inventory fields shared by update operations. +type InventoryUpdateBase struct { + AllocationRatio *float32 `json:"allocation_ratio,omitempty"` + MaxUnit *int `json:"max_unit,omitempty"` + MinUnit *int `json:"min_unit,omitempty"` + Reserved *int `json:"reserved,omitempty"` + StepSize *int `json:"step_size,omitempty"` + Total int `json:"total"` +} + // UpdateInventoriesOpts represents options used to update all inventories of a resource provider. -type UpdateInventoriesOpts = ResourceProviderInventories +type UpdateInventoriesOpts struct { + ResourceProviderGeneration int `json:"resource_provider_generation"` + Inventories map[string]InventoryUpdateBase `json:"inventories"` +} // ToResourceProviderUpdateInventoriesMap constructs a request body from UpdateInventoriesOpts. func (opts UpdateInventoriesOpts) ToResourceProviderUpdateInventoriesMap() (map[string]any, error) { @@ -214,7 +227,10 @@ type UpdateInventoryOptsBuilder interface { } // UpdateInventoryOpts represents options used to update one inventory of a resource provider. -type UpdateInventoryOpts = ResourceProviderInventory +type UpdateInventoryOpts struct { + ResourceProviderGeneration int `json:"resource_provider_generation"` + InventoryUpdateBase +} // ToResourceProviderUpdateInventoryMap constructs a request body from UpdateInventoryOpts. func (opts UpdateInventoryOpts) ToResourceProviderUpdateInventoryMap() (map[string]any, error) { diff --git a/openstack/placement/v1/resourceproviders/testing/fixtures_test.go b/openstack/placement/v1/resourceproviders/testing/fixtures_test.go index 45faff6427..b6bad2b920 100644 --- a/openstack/placement/v1/resourceproviders/testing/fixtures_test.go +++ b/openstack/placement/v1/resourceproviders/testing/fixtures_test.go @@ -5,6 +5,7 @@ import ( "net/http" "testing" + "github.com/gophercloud/gophercloud/v2/internal/ptr" "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/resourceproviders" th "github.com/gophercloud/gophercloud/v2/testhelper" @@ -823,3 +824,40 @@ func HandleResourceProviderUpdateAggregatesConflict(t *testing.T, fakeServer th. w.WriteHeader(http.StatusConflict) }) } + +// ToInventoryUpdateBase converts a ResourceProvider Inventory result into its +// corresponding Update (pointer) version. This is used in tests to facilitate +// the mapping between API results (which contain values) and Update operations +// (which use pointers for optionality). +func ToInventoryUpdateBase(inv resourceproviders.Inventory) resourceproviders.InventoryUpdateBase { + return resourceproviders.InventoryUpdateBase{ + AllocationRatio: ptr.To(inv.AllocationRatio), + MaxUnit: ptr.To(inv.MaxUnit), + MinUnit: ptr.To(inv.MinUnit), + Reserved: ptr.To(inv.Reserved), + StepSize: ptr.To(inv.StepSize), + Total: inv.Total, + } +} + +// ToUpdateInventoriesOpts converts a ResourceProviderInventories result into UpdateInventoriesOpts. +func ToUpdateInventoriesOpts(inventories resourceproviders.ResourceProviderInventories) resourceproviders.UpdateInventoriesOpts { + opts := resourceproviders.UpdateInventoriesOpts{ + ResourceProviderGeneration: inventories.ResourceProviderGeneration, + Inventories: make(map[string]resourceproviders.InventoryUpdateBase, len(inventories.Inventories)), + } + + for resourceClass, inv := range inventories.Inventories { + opts.Inventories[resourceClass] = ToInventoryUpdateBase(inv) + } + + return opts +} + +// ToUpdateInventoryOpts converts a ResourceProviderInventory result into UpdateInventoryOpts. +func ToUpdateInventoryOpts(inventory resourceproviders.ResourceProviderInventory) resourceproviders.UpdateInventoryOpts { + return resourceproviders.UpdateInventoryOpts{ + ResourceProviderGeneration: inventory.ResourceProviderGeneration, + InventoryUpdateBase: ToInventoryUpdateBase(inventory.Inventory), + } +} diff --git a/openstack/placement/v1/resourceproviders/testing/requests_test.go b/openstack/placement/v1/resourceproviders/testing/requests_test.go index 36909fb3df..73dd5428fb 100644 --- a/openstack/placement/v1/resourceproviders/testing/requests_test.go +++ b/openstack/placement/v1/resourceproviders/testing/requests_test.go @@ -153,7 +153,7 @@ func TestUpdateResourceProvidersInventories(t *testing.T) { HandleResourceProviderPutInventories(t, fakeServer) - opts := resourceproviders.UpdateInventoriesOpts(ExpectedInventories) + opts := ToUpdateInventoriesOpts(ExpectedInventories) actual, err := resourceproviders.UpdateInventories(context.TODO(), client.ServiceClient(fakeServer), ResourceProviderTestID, opts).Extract() th.AssertNoErr(t, err) th.AssertDeepEquals(t, ExpectedInventories, *actual) @@ -165,7 +165,7 @@ func TestUpdateResourceProvidersInventoriesNotFound(t *testing.T) { HandleResourceProviderPutInventoriesNotFound(t, fakeServer) - opts := resourceproviders.UpdateInventoriesOpts(ExpectedInventories) + opts := ToUpdateInventoriesOpts(ExpectedInventories) _, err := resourceproviders.UpdateInventories(context.TODO(), client.ServiceClient(fakeServer), NonExistentRPID, opts).Extract() th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } @@ -176,7 +176,7 @@ func TestUpdateResourceProviderInventory(t *testing.T) { HandleResourceProviderPutInventory(t, fakeServer) - opts := resourceproviders.UpdateInventoryOpts(ExpectedInventory) + opts := ToUpdateInventoryOpts(ExpectedInventory) actual, err := resourceproviders.UpdateInventory(context.TODO(), client.ServiceClient(fakeServer), ResourceProviderTestID, PresentInventoryResourceClass, opts).Extract() th.AssertNoErr(t, err) th.AssertDeepEquals(t, ExpectedInventory, *actual) @@ -188,7 +188,7 @@ func TestUpdateResourceProviderInventoryNotFound(t *testing.T) { HandleResourceProviderPutInventoryNotFound(t, fakeServer) - opts := resourceproviders.UpdateInventoryOpts(ExpectedInventory) + opts := ToUpdateInventoryOpts(ExpectedInventory) _, err := resourceproviders.UpdateInventory(context.TODO(), client.ServiceClient(fakeServer), NonExistentRPID, PresentInventoryResourceClass, opts).Extract() th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } From 26eb344dd68f3eccefceca0809bc3ce46070632d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 May 2026 14:49:52 +0000 Subject: [PATCH 393/429] build(deps): bump actions/labeler from 6.0.1 to 6.1.0 Bumps [actions/labeler](https://github.com/actions/labeler) from 6.0.1 to 6.1.0. - [Release notes](https://github.com/actions/labeler/releases) - [Commits](https://github.com/actions/labeler/compare/634933edcd8ababfe52f92936142cc22ac488b1b...f27b608878404679385c85cfa523b85ccb86e213) --- updated-dependencies: - dependency-name: actions/labeler dependency-version: 6.1.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/label-pr.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/label-pr.yaml b/.github/workflows/label-pr.yaml index 882a879b13..d1dee9da7b 100644 --- a/.github/workflows/label-pr.yaml +++ b/.github/workflows/label-pr.yaml @@ -109,4 +109,4 @@ jobs: contents: read pull-requests: write steps: - - uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6.0.1 + - uses: actions/labeler@f27b608878404679385c85cfa523b85ccb86e213 # v6.1.0 From 4949467cee83d1f0161592371c97ebd9817a33f0 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Wed, 13 May 2026 13:46:25 +0100 Subject: [PATCH 394/429] Add deprecation warning for V2EndpointURL, V3EndpointURL These are no longer used as of #3351. Mark them as deprecated so users know to migrate to their replacements. Signed-off-by: Stephen Finucane --- .golangci.yaml | 2 +- openstack/endpoint_location.go | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.golangci.yaml b/.golangci.yaml index 2de1155c03..1a197efa58 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -17,7 +17,7 @@ linters: rules: - linters: - staticcheck - text: "SA1019: (x509.EncryptPEMBlock|strings.Title)" + text: "SA1019: (x509.EncryptPEMBlock|strings.Title|openstack.V2EndpointURL|openstack.V3EndpointURL)" paths: - third_party$ - builtin$ diff --git a/openstack/endpoint_location.go b/openstack/endpoint_location.go index 573c1f06f4..579139c26d 100644 --- a/openstack/endpoint_location.go +++ b/openstack/endpoint_location.go @@ -19,6 +19,9 @@ to return. It's an error both when multiple endpoints match the provided criteria and when none do. The minimum that can be specified is a Type, but you will also often need to specify a Name and/or a Region depending on what's available on your OpenStack deployment. + +Deprecated: This function does not respect the [gophercloud.EndpointOpts.Version] parameter, +which can result in random endpoints being selected. Use [V2Endpoint] instead. */ func V2EndpointURL(catalog *tokens2.ServiceCatalog, opts gophercloud.EndpointOpts) (string, error) { // Extract Endpoints from the catalog entries that match the requested Type, Name if provided, and Region if provided. @@ -66,6 +69,9 @@ to return. It's an error both when multiple endpoints match the provided criteria and when none do. The minimum that can be specified is a Type, but you will also often need to specify a Name and/or a Region depending on what's available on your OpenStack deployment. + +Deprecated: This function does not respect the [gophercloud.EndpointOpts.Version] parameter, +which can result in random endpoint being selected. Use [V3Endpoint] instead. */ func V3EndpointURL(catalog *tokens3.ServiceCatalog, opts gophercloud.EndpointOpts) (string, error) { if opts.Availability != gophercloud.AvailabilityAdmin && From e09b30f9a37bca0a1e7bbe3c527520d68b3aa841 Mon Sep 17 00:00:00 2001 From: Dominik Danelski Date: Wed, 13 May 2026 19:22:12 +0200 Subject: [PATCH 395/429] Allow clearing Placement resource provider parent_provider_uuid Current implementation describes the possibility to set parent_provider_uuid for a child resource provider to detach it from its parent, but actually doesn't allow it due to the use of omitempty which would clear such nil input. To allow for this operation, I introduce the empty value of "" replaced by nil before being sent. This pattern allows for parent_provider_uuid to remain an optional argument just as in the API. Such pattern was previously introduced in DNS recordsets. Fixes #3746 Signed-off-by: Dominik Danelski --- .../placement/v1/resourceproviders_test.go | 38 +++++++++++++++++++ .../placement/v1/resourceproviders/doc.go | 33 +++++++++++++--- .../v1/resourceproviders/requests.go | 18 ++++++--- .../testing/requests_test.go | 33 ++++++++++++++++ 4 files changed, 111 insertions(+), 11 deletions(-) diff --git a/internal/acceptance/openstack/placement/v1/resourceproviders_test.go b/internal/acceptance/openstack/placement/v1/resourceproviders_test.go index 4b2f70d819..ee4e22ec9c 100644 --- a/internal/acceptance/openstack/placement/v1/resourceproviders_test.go +++ b/internal/acceptance/openstack/placement/v1/resourceproviders_test.go @@ -627,3 +627,41 @@ func TestResourceProviderUpdateAggregatesPreGenerationWithGenerationSuccess(t *t th.AssertEquals(t, true, slices.Contains(after.Aggregates, aggregate)) } } + +func TestResourceProviderParentDetach(t *testing.T) { + clients.RequireAdmin(t) + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + // Arrange: Create a parent resource provider + parentProvider, err := CreateResourceProvider(t, client) + th.AssertNoErr(t, err) + defer DeleteResourceProvider(t, client, parentProvider.UUID) + + // Arrange: Create a child resource provider with that parent + childProvider, err := CreateResourceProviderWithParent(t, client, parentProvider.UUID) + th.AssertNoErr(t, err) + defer DeleteResourceProvider(t, client, childProvider.UUID) + + // Sanity check: Verify that the child provider has the correct parent before the update + th.AssertEquals(t, parentProvider.UUID, childProvider.ParentProviderUUID) + + // Act: Update the child resource provider to remove the parent (transform to root) + client.Microversion = "1.37" + empty := "" + updateOpts := resourceproviders.UpdateOpts{ + Name: &childProvider.Name, + ParentProviderUUID: &empty, + } + updatedChild, err := resourceproviders.Update(context.TODO(), client, childProvider.UUID, updateOpts).Extract() + th.AssertNoErr(t, err) + + // Assert: Verify that the ParentProviderUUID is now null (empty string in Gophercloud result struct) + th.AssertEquals(t, "", updatedChild.ParentProviderUUID) + + // Assert: Double check with a Get request + childGet, err := resourceproviders.Get(context.TODO(), client, childProvider.UUID).Extract() + th.AssertNoErr(t, err) + th.AssertEquals(t, "", childGet.ParentProviderUUID) +} diff --git a/openstack/placement/v1/resourceproviders/doc.go b/openstack/placement/v1/resourceproviders/doc.go index d0a6caa515..120affca67 100644 --- a/openstack/placement/v1/resourceproviders/doc.go +++ b/openstack/placement/v1/resourceproviders/doc.go @@ -20,9 +20,9 @@ Example to list resource providers Example to create resource providers createOpts := resourceproviders.CreateOpts{ - Name: "new-rp", - UUID: "b99b3ab4-3aa6-4fba-b827-69b88b9c544a", - ParentProvider: "c7f50b40-6f32-4d7a-9f32-9384057be83b" + Name: "new-rp", + UUID: "b99b3ab4-3aa6-4fba-b827-69b88b9c544a", + ParentProviderUUID: "c7f50b40-6f32-4d7a-9f32-9384057be83b", } rp, err := resourceproviders.Create(context.TODO(), placementClient, createOpts).Extract() @@ -49,14 +49,35 @@ Example to Get a resource provider Example to Update a resource provider resourceProviderID := "b99b3ab4-3aa6-4fba-b827-69b88b9c544a" + name := "new-rp" + parent := "c7f50b40-6f32-4d7a-9f32-9384057be83b" updateOpts := resourceproviders.UpdateOpts{ - Name: "new-rp", - ParentProvider: "c7f50b40-6f32-4d7a-9f32-9384057be83b" + Name: &name, + ParentProviderUUID: &parent, } placementClient.Microversion = "1.37" - resourceProvider, err := resourceproviders.Update(context.TODO(), placementClient, resourceProviderID).Extract() + resourceProvider, err := resourceproviders.Update(context.TODO(), placementClient, resourceProviderID, updateOpts).Extract() + if err != nil { + panic(err) + } + +Example to transform a provider to a new root provider (set parent_provider_uuid to null). +Note that Gophercloud uses an empty string as a sentinel value to represent JSON null +for this optional field. + + resourceProviderID := "b99b3ab4-3aa6-4fba-b827-69b88b9c544a" + name := "existing-rp" + parent := "" + + updateOpts := resourceproviders.UpdateOpts{ + Name: &name, + ParentProviderUUID: &parent, + } + + placementClient.Microversion = "1.37" + resourceProvider, err = resourceproviders.Update(context.TODO(), placementClient, resourceProviderID, updateOpts).Extract() if err != nil { panic(err) } diff --git a/openstack/placement/v1/resourceproviders/requests.go b/openstack/placement/v1/resourceproviders/requests.go index aecc975060..603d8eea7f 100644 --- a/openstack/placement/v1/resourceproviders/requests.go +++ b/openstack/placement/v1/resourceproviders/requests.go @@ -126,16 +126,24 @@ type UpdateOptsBuilder interface { type UpdateOpts struct { Name *string `json:"name,omitempty"` // Available in version >= 1.37. It can be set to any existing provider UUID - // except to providers that would cause a loop. Also it can be set to null - // to transform the provider to a new root provider. This operation needs to - // be used carefully. Moving providers can mean that the original rules used - // to create the existing resource allocations may be invalidated by that move. + // except to providers that would cause a loop. Using an empty string + // transforms the provider to a new root provider. ParentProviderUUID *string `json:"parent_provider_uuid,omitempty"` } // ToResourceProviderUpdateMap constructs a request body from UpdateOpts. func (opts UpdateOpts) ToResourceProviderUpdateMap() (map[string]any, error) { - return gophercloud.BuildRequestBody(opts, "") + b, err := gophercloud.BuildRequestBody(opts, "") + if err != nil { + return nil, err + } + + // In order to set this to null, use an empty string as a value. + if opts.ParentProviderUUID != nil && *opts.ParentProviderUUID == "" { + b["parent_provider_uuid"] = nil + } + + return b, nil } // Update makes a request against the API to create a resource provider diff --git a/openstack/placement/v1/resourceproviders/testing/requests_test.go b/openstack/placement/v1/resourceproviders/testing/requests_test.go index 36909fb3df..1e316c46ff 100644 --- a/openstack/placement/v1/resourceproviders/testing/requests_test.go +++ b/openstack/placement/v1/resourceproviders/testing/requests_test.go @@ -104,6 +104,39 @@ func TestUpdate(t *testing.T) { th.AssertEquals(t, rp.ParentProviderUUID, parentProviderUUID) } +func TestUpdateParentProviderUUID(t *testing.T) { + // 1. Test non-empty UUID + uuid := "b99b3ab4-3aa6-4fba-b827-69b88b9c544a" + opts := resourceproviders.UpdateOpts{ + ParentProviderUUID: &uuid, + } + actual, err := opts.ToResourceProviderUpdateMap() + th.AssertNoErr(t, err) + expected := map[string]any{ + "parent_provider_uuid": uuid, + } + th.AssertDeepEquals(t, expected, actual) + + // 2. Test empty string sentinel (should be null) + empty := "" + opts = resourceproviders.UpdateOpts{ + ParentProviderUUID: &empty, + } + actual, err = opts.ToResourceProviderUpdateMap() + th.AssertNoErr(t, err) + expected = map[string]any{ + "parent_provider_uuid": nil, + } + th.AssertDeepEquals(t, expected, actual) + + // 3. Test nil (should be omitted) + opts = resourceproviders.UpdateOpts{} + actual, err = opts.ToResourceProviderUpdateMap() + th.AssertNoErr(t, err) + expected = map[string]any{} + th.AssertDeepEquals(t, expected, actual) +} + func TestGetResourceProvidersUsages(t *testing.T) { fakeServer := th.SetupHTTP() defer fakeServer.Teardown() From 72ca60591c71c0635598daf7e6bd446b92b0869f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 May 2026 09:23:00 +0000 Subject: [PATCH 396/429] build(deps): bump github/codeql-action from 4.35.2 to 4.35.4 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.35.2 to 4.35.4. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/95e58e9a2cdfd71adc6e0353d5c52f41a045d225...68bde559dea0fdcac2102bfdf6230c5f70eb485e) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 4.35.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql-analysis.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yaml b/.github/workflows/codeql-analysis.yaml index 813e1e3034..1b193af350 100644 --- a/.github/workflows/codeql-analysis.yaml +++ b/.github/workflows/codeql-analysis.yaml @@ -29,12 +29,12 @@ jobs: cache: true - name: Initialize CodeQL - uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 + uses: github/codeql-action/init@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 + uses: github/codeql-action/autobuild@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 + uses: github/codeql-action/analyze@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4 From 9be9846ceba7868feef54d567a86228439050b96 Mon Sep 17 00:00:00 2001 From: Winicius Silva Date: Thu, 14 May 2026 20:10:11 +0100 Subject: [PATCH 397/429] fix(vpnaas): change encryption and auth method on acceptance tests The SHA1, MD5, DES, and 3DES were deprecated in a recent neutron-vpnaas patch[1], leading functional-network tests to fail, because it was still using the deprecated algorithms when creating IKEPolicies and IPSecPolicies. [1] https://review.opendev.org/c/openstack/neutron-vpnaas/+/982383 --- .../openstack/networking/v2/extensions/vpnaas/vpnaas.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/internal/acceptance/openstack/networking/v2/extensions/vpnaas/vpnaas.go b/internal/acceptance/openstack/networking/v2/extensions/vpnaas/vpnaas.go index 07b9e38839..76652134ea 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/vpnaas/vpnaas.go +++ b/internal/acceptance/openstack/networking/v2/extensions/vpnaas/vpnaas.go @@ -61,7 +61,9 @@ func CreateIPSecPolicy(t *testing.T, client *gophercloud.ServiceClient) (*ipsecp t.Logf("Attempting to create IPSec policy %s", policyName) createOpts := ipsecpolicies.CreateOpts{ - Name: policyName, + Name: policyName, + EncryptionAlgorithm: ipsecpolicies.EncryptionAlgorithmAES128, + AuthAlgorithm: ipsecpolicies.AuthAlgorithmAESCMAC, } policy, err := ipsecpolicies.Create(context.TODO(), client, createOpts).Extract() @@ -85,8 +87,9 @@ func CreateIKEPolicy(t *testing.T, client *gophercloud.ServiceClient) (*ikepolic createOpts := ikepolicies.CreateOpts{ Name: policyName, - EncryptionAlgorithm: ikepolicies.EncryptionAlgorithm3DES, + EncryptionAlgorithm: ikepolicies.EncryptionAlgorithmAES128, PFS: ikepolicies.PFSGroup5, + AuthAlgorithm: ikepolicies.AuthAlgorithmSHA256, } policy, err := ikepolicies.Create(context.TODO(), client, createOpts).Extract() @@ -195,7 +198,6 @@ func DeleteEndpointGroup(t *testing.T, client *gophercloud.ServiceClient, epGrou } t.Logf("Deleted endpoint group: %s", epGroupID) - } // CreateEndpointGroupWithSubnet will create an endpoint group with a random name. From 740255e6aead7eebccf97b7477b7a077b9a935ca Mon Sep 17 00:00:00 2001 From: Dominik Danelski Date: Mon, 18 May 2026 11:45:45 +0200 Subject: [PATCH 398/429] Add Placement resourceprovider list post 1.39 Allows for repeating required and member_of arguments. Change of the type of field, microversions.go required. Related #526 Signed-off-by: Dominik Danelski --- .../openstack/placement/v1/placement.go | 11 +++ .../placement/v1/resourceproviders_test.go | 76 +++++++++++++++++++ .../placement/v1/resourceproviders/doc.go | 23 ++++++ .../v1/resourceproviders/microversions.go | 40 ++++++++++ .../testing/fixtures_test.go | 19 +++++ .../testing/requests_test.go | 27 +++++++ 6 files changed, 196 insertions(+) create mode 100644 openstack/placement/v1/resourceproviders/microversions.go diff --git a/internal/acceptance/openstack/placement/v1/placement.go b/internal/acceptance/openstack/placement/v1/placement.go index 18c3304075..977b59459d 100644 --- a/internal/acceptance/openstack/placement/v1/placement.go +++ b/internal/acceptance/openstack/placement/v1/placement.go @@ -10,6 +10,13 @@ import ( th "github.com/gophercloud/gophercloud/v2/testhelper" ) +func restoreClientMicroversion(client *gophercloud.ServiceClient) func() { + originalMicroversion := client.Microversion + return func() { + client.Microversion = originalMicroversion + } +} + func CreateResourceProvider(t *testing.T, client *gophercloud.ServiceClient) (*resourceproviders.ResourceProvider, error) { name := tools.RandomString("TESTACC-", 8) t.Logf("Attempting to create resource provider: %s", name) @@ -18,6 +25,8 @@ func CreateResourceProvider(t *testing.T, client *gophercloud.ServiceClient) (*r Name: name, } + defer restoreClientMicroversion(client)() + client.Microversion = "1.20" resourceProvider, err := resourceproviders.Create(context.TODO(), client, createOpts).Extract() if err != nil { @@ -41,6 +50,8 @@ func CreateResourceProviderWithParent(t *testing.T, client *gophercloud.ServiceC ParentProviderUUID: parentUUID, } + defer restoreClientMicroversion(client)() + client.Microversion = "1.20" resourceProvider, err := resourceproviders.Create(context.TODO(), client, createOpts).Extract() if err != nil { diff --git a/internal/acceptance/openstack/placement/v1/resourceproviders_test.go b/internal/acceptance/openstack/placement/v1/resourceproviders_test.go index 4b2f70d819..e732f773c6 100644 --- a/internal/acceptance/openstack/placement/v1/resourceproviders_test.go +++ b/internal/acceptance/openstack/placement/v1/resourceproviders_test.go @@ -6,12 +6,14 @@ import ( "context" "net/http" "slices" + "strings" "testing" "github.com/gophercloud/gophercloud/v2" "github.com/gophercloud/gophercloud/v2/internal/acceptance/clients" "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/resourceproviders" + "github.com/gophercloud/gophercloud/v2/openstack/placement/v1/traits" th "github.com/gophercloud/gophercloud/v2/testhelper" ) @@ -35,6 +37,76 @@ func TestResourceProviderList(t *testing.T) { } } +func TestResourceProviderList139(t *testing.T) { + clients.RequireAdmin(t) + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + client.Microversion = "1.39" + + // Arrange: Create a resource provider, traits, and aggregates. + // Assign them to the created RP. + resourceProvider, err := CreateResourceProvider(t, client) + th.AssertNoErr(t, err) + defer DeleteResourceProvider(t, client, resourceProvider.UUID) + + trait1 := strings.ToUpper(tools.RandomString("CUSTOM_", 8)) + trait2 := strings.ToUpper(tools.RandomString("CUSTOM_", 8)) + err = traits.Create(context.TODO(), client, trait1).ExtractErr() + th.AssertNoErr(t, err) + defer traits.Delete(context.TODO(), client, trait1) + err = traits.Create(context.TODO(), client, trait2).ExtractErr() + th.AssertNoErr(t, err) + defer traits.Delete(context.TODO(), client, trait2) + + currentTraits, err := resourceproviders.GetTraits(context.TODO(), client, resourceProvider.UUID).Extract() + th.AssertNoErr(t, err) + + _, err = resourceproviders.UpdateTraits(context.TODO(), client, resourceProvider.UUID, resourceproviders.UpdateTraitsOpts{ + ResourceProviderGeneration: currentTraits.ResourceProviderGeneration, + Traits: []string{trait1, trait2}, + }).Extract() + th.AssertNoErr(t, err) + + currentAggregates, err := resourceproviders.GetAggregates(context.TODO(), client, resourceProvider.UUID).Extract() + th.AssertNoErr(t, err) + + aggregate1 := tools.RandomUUID() + aggregate2 := tools.RandomUUID() + aggregate3 := tools.RandomUUID() + _, err = resourceproviders.UpdateAggregates(context.TODO(), client, resourceProvider.UUID, resourceproviders.UpdateAggregatesOpts{ + ResourceProviderGeneration: currentAggregates.ResourceProviderGeneration, + Aggregates: []string{aggregate1, aggregate2}, + }).Extract() + th.AssertNoErr(t, err) + + listOpts := resourceproviders.ListOpts139{ + // Repeating member_of means AND: provider must be in aggregate1 and in any of (aggregate2, aggregate3). + // We'll expect list to return our provider. + MemberOf: []string{aggregate1, "in:" + aggregate2 + "," + aggregate3}, + Required: []string{trait1, trait2}, + } + + // Act: List resource providers with the above traits and aggregates as filters. + allPages, err := resourceproviders.List(client, listOpts).AllPages(context.TODO()) + th.AssertNoErr(t, err) + + // Assert: Our resource provider is in the results and has the traits and aggregates we set. + allResourceProviders, err := resourceproviders.ExtractResourceProviders(allPages) + th.AssertNoErr(t, err) + th.AssertEquals(t, true, len(allResourceProviders) > 0) + + found := false + for _, rp := range allResourceProviders { + if rp.UUID == resourceProvider.UUID { + found = true + break + } + } + th.AssertEquals(t, true, found) +} + func TestResourceProvider(t *testing.T) { clients.SkipRelease(t, "stable/mitaka") clients.SkipRelease(t, "stable/newton") @@ -311,6 +383,8 @@ func TestResourceProviderDeleteInventoriesSuccess(t *testing.T) { client, err := clients.NewPlacementV1Client() th.AssertNoErr(t, err) + client.Microversion = "1.20" + resourceProvider, err := CreateResourceProvider(t, client) th.AssertNoErr(t, err) defer DeleteResourceProvider(t, client, resourceProvider.UUID) @@ -422,6 +496,8 @@ func TestResourceProviderTraits(t *testing.T) { client, err := clients.NewPlacementV1Client() th.AssertNoErr(t, err) + client.Microversion = "1.20" + // first create new resource provider resourceProvider, err := CreateResourceProvider(t, client) th.AssertNoErr(t, err) diff --git a/openstack/placement/v1/resourceproviders/doc.go b/openstack/placement/v1/resourceproviders/doc.go index d0a6caa515..46d022daf5 100644 --- a/openstack/placement/v1/resourceproviders/doc.go +++ b/openstack/placement/v1/resourceproviders/doc.go @@ -17,6 +17,29 @@ Example to list resource providers fmt.Printf("%+v\n", r) } +Example to list resource providers with repeating member_of and required parameters (microversion >= 1.39) + + placementClient.Microversion = "1.39" + + listOpts := resourceproviders.ListOpts139{ + MemberOf: []string{"42896e0d-205d-4fe3-bd1e-100924931787", "in:7834d585-31d4-486f-be8c-b3c1a58ca710,5e08ea53-c4c6-448e-9334-ac4953de3cfa"}, + Required: []string{"CUSTOM_TRAIT1", "CUSTOM_TRAIT2"}, + } + + allPages, err := resourceproviders.List(placementClient, listOpts).AllPages(context.TODO()) + if err != nil { + panic(err) + } + + allResourceProviders, err := resourceproviders.ExtractResourceProviders(allPages) + if err != nil { + panic(err) + } + + for _, r := range allResourceProviders { + fmt.Printf("%+v\n", r) + } + Example to create resource providers createOpts := resourceproviders.CreateOpts{ diff --git a/openstack/placement/v1/resourceproviders/microversions.go b/openstack/placement/v1/resourceproviders/microversions.go new file mode 100644 index 0000000000..607688212a --- /dev/null +++ b/openstack/placement/v1/resourceproviders/microversions.go @@ -0,0 +1,40 @@ +package resourceproviders + +import "github.com/gophercloud/gophercloud/v2" + +// ListOpts139 allows filtering resource providers. Filtering is achieved by +// passing in struct field values that map to the resource provider +// attributes you want to see returned. +// ListOpts139 is available in version >= 1.39. +type ListOpts139 struct { + // Name is the name of the resource provider to filter the list + Name string `q:"name"` + + // UUID is the uuid of the resource provider to filter the list + UUID string `q:"uuid"` + + // MemberOf is a list representing aggregate uuids that a provider must be + // associated with to be returned. + // Alternative is defined using the in: syntax, e.g. member_of=in:agg1,agg2,agg3. + // Forbidden aggregates are prefixed with !. + // Starting with microversion 1.24, the member_of parameter may be repeated. + MemberOf []string `q:"member_of"` + + // Resources is a comma-separated list of string indicating an amount of resource + // of a specified class that a provider must have the capacity and availability to serve + Resources string `q:"resources"` + + // InTree is a string that represents a resource provider UUID. The returned resource + // providers will be in the same provider tree as the specified provider. + InTree string `q:"in_tree"` + + // Required is a list of trait names. + // Microversion 1.39 added support for repeating the required parameter and for the in: syntax. + Required []string `q:"required"` +} + +// ToResourceProviderListQuery formats a ListOpts139 into a query string. +func (opts ListOpts139) ToResourceProviderListQuery() (string, error) { + q, err := gophercloud.BuildQueryString(opts) + return q.String(), err +} diff --git a/openstack/placement/v1/resourceproviders/testing/fixtures_test.go b/openstack/placement/v1/resourceproviders/testing/fixtures_test.go index 45faff6427..7299162eb0 100644 --- a/openstack/placement/v1/resourceproviders/testing/fixtures_test.go +++ b/openstack/placement/v1/resourceproviders/testing/fixtures_test.go @@ -433,6 +433,25 @@ func HandleResourceProviderList(t *testing.T, fakeServer th.FakeServer) { }) } +func HandleResourceProviderList139(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/resource_providers", + func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + q := r.URL.Query() + th.AssertDeepEquals(t, + []string{"a09ba171-9405-40ca-bfe1-a8d1208af2ed", "47abce38-8a58-47b3-81e0-c647e37e03ae"}, + q["member_of"]) + th.AssertDeepEquals(t, []string{"HW:A_TRAIT", "CUSTOM_TRAIT"}, q["required"]) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, ResourceProvidersBody) + }) +} + func HandleResourceProviderCreate(t *testing.T, fakeServer th.FakeServer) { fakeServer.Mux.HandleFunc("/resource_providers", func(w http.ResponseWriter, r *http.Request) { th.TestMethod(t, r, "POST") diff --git a/openstack/placement/v1/resourceproviders/testing/requests_test.go b/openstack/placement/v1/resourceproviders/testing/requests_test.go index 36909fb3df..205a2c0c3e 100644 --- a/openstack/placement/v1/resourceproviders/testing/requests_test.go +++ b/openstack/placement/v1/resourceproviders/testing/requests_test.go @@ -40,6 +40,33 @@ func TestListResourceProviders(t *testing.T) { } } +func TestListResourceProviders139(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + HandleResourceProviderList139(t, fakeServer) + + count := 0 + opts := resourceproviders.ListOpts139{ + MemberOf: []string{"a09ba171-9405-40ca-bfe1-a8d1208af2ed", "47abce38-8a58-47b3-81e0-c647e37e03ae"}, + Required: []string{"HW:A_TRAIT", "CUSTOM_TRAIT"}, + } + err := resourceproviders.List(client.ServiceClient(fakeServer), opts).EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) { + count++ + + actual, err := resourceproviders.ExtractResourceProviders(page) + if err != nil { + t.Errorf("Failed to extract resource providers: %v", err) + return false, err + } + th.AssertDeepEquals(t, ExpectedResourceProviders, actual) + + return true, nil + }) + + th.AssertNoErr(t, err) +} + func TestCreateResourceProvider(t *testing.T) { fakeServer := th.SetupHTTP() defer fakeServer.Teardown() From 56eeec07a4d6ceadb84c8525ba7a48e9f4dc970b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 May 2026 17:09:09 +0000 Subject: [PATCH 399/429] build(deps): bump golang.org/x/crypto from 0.50.0 to 0.51.0 Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.50.0 to 0.51.0. - [Commits](https://github.com/golang/crypto/compare/v0.50.0...v0.51.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-version: 0.51.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 37b304d220..f2f4598ea8 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.25.0 require ( go.yaml.in/yaml/v3 v3.0.4 - golang.org/x/crypto v0.50.0 + golang.org/x/crypto v0.51.0 ) -require golang.org/x/sys v0.43.0 // indirect +require golang.org/x/sys v0.44.0 // indirect diff --git a/go.sum b/go.sum index 7086387134..d85ec14b2c 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,10 @@ go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= -golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q= -golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= -golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY= -golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY= +golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI= +golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8= +golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ= +golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4= +golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From b5e89e58c9b48c60307e30072d1330509205b81b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 May 2026 09:29:40 +0000 Subject: [PATCH 400/429] build(deps): bump zizmorcore/zizmor-action from 0.5.3 to 0.5.5 Bumps [zizmorcore/zizmor-action](https://github.com/zizmorcore/zizmor-action) from 0.5.3 to 0.5.5. - [Release notes](https://github.com/zizmorcore/zizmor-action/releases) - [Commits](https://github.com/zizmorcore/zizmor-action/compare/b1d7e1fb5de872772f31590499237e7cce841e8e...a16621b09c6db4281f81a93cb393b05dcd7b7165) --- updated-dependencies: - dependency-name: zizmorcore/zizmor-action dependency-version: 0.5.5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/zizmor.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/zizmor.yaml b/.github/workflows/zizmor.yaml index d07c30355a..c796e278a1 100644 --- a/.github/workflows/zizmor.yaml +++ b/.github/workflows/zizmor.yaml @@ -25,4 +25,4 @@ jobs: persist-credentials: false - name: Run zizmor - uses: zizmorcore/zizmor-action@b1d7e1fb5de872772f31590499237e7cce841e8e # v0.5.3 + uses: zizmorcore/zizmor-action@a16621b09c6db4281f81a93cb393b05dcd7b7165 # v0.5.5 From 4ebcbe01d767230579223f6783b32c8b4ed833d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 22 May 2026 09:28:34 +0000 Subject: [PATCH 401/429] build(deps): bump github/codeql-action from 4.35.4 to 4.35.5 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.35.4 to 4.35.5. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/68bde559dea0fdcac2102bfdf6230c5f70eb485e...9e0d7b8d25671d64c341c19c0152d693099fb5ba) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 4.35.5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql-analysis.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yaml b/.github/workflows/codeql-analysis.yaml index 1b193af350..b3f415da50 100644 --- a/.github/workflows/codeql-analysis.yaml +++ b/.github/workflows/codeql-analysis.yaml @@ -29,12 +29,12 @@ jobs: cache: true - name: Initialize CodeQL - uses: github/codeql-action/init@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4 + uses: github/codeql-action/init@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4 + uses: github/codeql-action/autobuild@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4 + uses: github/codeql-action/analyze@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5 From 9bc86df5023acf6a593933ef7c16fabbdfc35053 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 May 2026 14:11:41 +0000 Subject: [PATCH 402/429] build(deps): bump zizmorcore/zizmor-action from 0.5.5 to 0.5.6 Bumps [zizmorcore/zizmor-action](https://github.com/zizmorcore/zizmor-action) from 0.5.5 to 0.5.6. - [Release notes](https://github.com/zizmorcore/zizmor-action/releases) - [Commits](https://github.com/zizmorcore/zizmor-action/compare/a16621b09c6db4281f81a93cb393b05dcd7b7165...5f14fd08f7cf1cb1609c1e344975f152c7ee938d) --- updated-dependencies: - dependency-name: zizmorcore/zizmor-action dependency-version: 0.5.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/zizmor.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/zizmor.yaml b/.github/workflows/zizmor.yaml index c796e278a1..8258e9c0f5 100644 --- a/.github/workflows/zizmor.yaml +++ b/.github/workflows/zizmor.yaml @@ -25,4 +25,4 @@ jobs: persist-credentials: false - name: Run zizmor - uses: zizmorcore/zizmor-action@a16621b09c6db4281f81a93cb393b05dcd7b7165 # v0.5.5 + uses: zizmorcore/zizmor-action@5f14fd08f7cf1cb1609c1e344975f152c7ee938d # v0.5.6 From b142ffd88b33e749d7066e2b243c6ac6fa7397d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?p=C3=BDrus?= Date: Tue, 26 May 2026 11:25:58 +0200 Subject: [PATCH 403/429] neutron: properly enable port-forwarding extension in devstack --- .github/workflows/functional-networking.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/functional-networking.yaml b/.github/workflows/functional-networking.yaml index 85d71c51f8..6d4522ac64 100644 --- a/.github/workflows/functional-networking.yaml +++ b/.github/workflows/functional-networking.yaml @@ -66,16 +66,16 @@ jobs: with: branch: ${{ matrix.openstack_version }} conf_overrides: | + enable_plugin neutron https://opendev.org/openstack/neutron ${{ matrix.openstack_version }} enable_plugin neutron-dynamic-routing https://github.com/openstack/neutron-dynamic-routing ${{ matrix.openstack_version }} enable_plugin neutron-vpnaas https://github.com/openstack/neutron-vpnaas ${{ matrix.openstack_version }} enable_plugin networking-bgpvpn https://github.com/openstack/networking-bgpvpn.git ${{ matrix.openstack_version }} - Q_ML2_PLUGIN_EXT_DRIVERS=qos,port_security,dns_domain_keywords,port_trusted BGP_SCHEDULER_DRIVER=neutron_dynamic_routing.services.bgp.scheduler.bgp_dragent_scheduler.StaticScheduler [[post-config|\$NEUTRON_CONF]] [oslo_policy] policy_dirs = /tmp/neutron-policies - enabled_services: "neutron-dns,neutron-qos,neutron-segments,neutron-trunk,neutron-uplink-status-propagation,neutron-network-segment-range,neutron-port-forwarding,openstack-cli-server" + enabled_services: "neutron-dns,neutron-qos,neutron-segments,neutron-trunk,neutron-port-trusted-vif,neutron-uplink-status-propagation,neutron-network-segment-range,neutron-port-forwarding,openstack-cli-server" - name: Checkout go if: ${{ fromJSON(steps.changed-files.outputs.matches) }} From f55c24b994872eaa6762c4f3f555cf69f610b5fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Wed, 27 May 2026 16:21:18 +0200 Subject: [PATCH 404/429] CI: Use pre-built amphora images for Octavia jobs The octavia master job started failing recently while building the amphora image with diskimage-builder. Instead of building images from scratch (which is fragile and slow), download pre-built test images from https://tarballs.opendev.org/openstack/octavia/test-images/. The Octavia devstack plugin skips the DIB build when the image file already exists at the path specified by OCTAVIA_AMP_IMAGE_FILE. --- .github/workflows/functional-loadbalancer.yaml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/functional-loadbalancer.yaml b/.github/workflows/functional-loadbalancer.yaml index 52dc11662e..62103ce327 100644 --- a/.github/workflows/functional-loadbalancer.yaml +++ b/.github/workflows/functional-loadbalancer.yaml @@ -15,21 +15,21 @@ jobs: - name: "master" openstack_version: "master" ubuntu_version: "24.04" + amphora_image_url: "https://tarballs.opendev.org/openstack/octavia/test-images/test-only-amphora-x64-haproxy-ubuntu-noble.qcow2" devstack_conf_overrides: | LIBVIRT_CPU_MODE=host-passthrough - OCTAVIA_AMP_DISTRIBUTION_RELEASE_ID=jammy - name: "gazpacho" openstack_version: "stable/2026.1" ubuntu_version: "24.04" + amphora_image_url: "https://tarballs.opendev.org/openstack/octavia/test-images/test-only-amphora-x64-haproxy-ubuntu-noble.qcow2" devstack_conf_overrides: | LIBVIRT_CPU_MODE=host-passthrough - OCTAVIA_AMP_DISTRIBUTION_RELEASE_ID=jammy - name: "epoxy" openstack_version: "stable/2025.1" ubuntu_version: "24.04" + amphora_image_url: "https://tarballs.opendev.org/openstack/octavia/test-images/test-only-amphora-x64-haproxy-ubuntu-jammy.qcow2" devstack_conf_overrides: | LIBVIRT_CPU_MODE=host-passthrough - OCTAVIA_AMP_DISTRIBUTION_RELEASE_ID=jammy runs-on: ubuntu-${{ matrix.ubuntu_version }} name: Octavia on OpenStack ${{ matrix.name }} steps: @@ -59,6 +59,11 @@ jobs: echo "No relevant files changed - skipping tests for ${{ matrix.name }}" echo "TESTS_SKIPPED=true" >> $GITHUB_ENV + - name: Download pre-built amphora image + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} + run: | + wget -q "${{ matrix.amphora_image_url }}" -O /tmp/amphora-x64-haproxy.qcow2 + - name: Deploy devstack if: ${{ fromJSON(steps.changed-files.outputs.matches) }} uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 # v0.19 @@ -67,6 +72,7 @@ jobs: conf_overrides: | enable_plugin octavia https://github.com/openstack/octavia ${{ matrix.openstack_version }} enable_plugin neutron https://github.com/openstack/neutron ${{ matrix.openstack_version }} + OCTAVIA_AMP_IMAGE_FILE=/tmp/amphora-x64-haproxy.qcow2 ${{ matrix.devstack_conf_overrides }} enabled_services: "octavia,o-api,o-cw,o-hk,o-hm,o-da,neutron-qos,openstack-cli-server" From ef1e621dfcabc53c2f59c21ea03ac99436f4fa87 Mon Sep 17 00:00:00 2001 From: Adam Sharp <46480158+Sharpz7@users.noreply.github.com> Date: Wed, 27 May 2026 17:53:21 +0200 Subject: [PATCH 405/429] Add support for listing recordsets across all zones This change introduces a new ListAll function and helper URL builder to expose the Designate /recordsets endpoint via gophercloud. This allows callers to retrieve recordsets across all zones, in addition to the existing per-zone ListByZone helper. The new ListAll function: - Reuses the existing ListOpts/ListOptsBuilder types for filtering, sorting, and pagination. - Returns a pagination.Pager consistent with other list operations in this package. --- .../openstack/dns/v2/recordsets_test.go | 43 +++++++++++++++ openstack/dns/v2/recordsets/requests.go | 19 ++++++- .../v2/recordsets/testing/fixtures_test.go | 37 ++++++++----- .../v2/recordsets/testing/requests_test.go | 52 +++++++++++++++++++ openstack/dns/v2/recordsets/urls.go | 4 ++ 5 files changed, 140 insertions(+), 15 deletions(-) diff --git a/internal/acceptance/openstack/dns/v2/recordsets_test.go b/internal/acceptance/openstack/dns/v2/recordsets_test.go index fd2e4d41bf..7030791f6d 100644 --- a/internal/acceptance/openstack/dns/v2/recordsets_test.go +++ b/internal/acceptance/openstack/dns/v2/recordsets_test.go @@ -52,6 +52,49 @@ func TestRecordSetsListByZone(t *testing.T) { th.AssertNoErr(t, err) } +func TestRecordSetsListAll(t *testing.T) { + client, err := clients.NewDNSV2Client() + th.AssertNoErr(t, err) + + zone, err := CreateZone(t, client) + th.AssertNoErr(t, err) + defer DeleteZone(t, client, zone) + + rs, err := CreateRecordSet(t, client, zone) + th.AssertNoErr(t, err) + defer DeleteRecordSet(t, client, rs) + + allPages, err := recordsets.ListAll(client, nil).AllPages(context.TODO()) + th.AssertNoErr(t, err) + + allRecordSets, err := recordsets.ExtractRecordSets(allPages) + th.AssertNoErr(t, err) + + var found bool + for _, recordset := range allRecordSets { + tools.PrintResource(t, &recordset) + + if recordset.ID == rs.ID { + found = true + } + } + + th.AssertEquals(t, found, true) + + listOpts := recordsets.ListOpts{ + Limit: 1, + } + + pager := recordsets.ListAll(client, listOpts) + err = pager.EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) { + rr, err := recordsets.ExtractRecordSets(page) + th.AssertNoErr(t, err) + th.AssertEquals(t, len(rr), 1) + return false, nil + }) + th.AssertNoErr(t, err) +} + func TestRecordSetsCRUD(t *testing.T) { client, err := clients.NewDNSV2Client() th.AssertNoErr(t, err) diff --git a/openstack/dns/v2/recordsets/requests.go b/openstack/dns/v2/recordsets/requests.go index 49e629b393..2bf952446c 100644 --- a/openstack/dns/v2/recordsets/requests.go +++ b/openstack/dns/v2/recordsets/requests.go @@ -42,7 +42,7 @@ func (opts ListOpts) ToRecordSetListQuery() (string, error) { return q.String(), err } -// ListByZone implements the recordset list request. +// ListByZone implements the recordset list request for a specific zone. func ListByZone(client *gophercloud.ServiceClient, zoneID string, opts ListOptsBuilder) pagination.Pager { url := baseURL(client, zoneID) if opts != nil { @@ -57,6 +57,21 @@ func ListByZone(client *gophercloud.ServiceClient, zoneID string, opts ListOptsB }) } +// ListAll implements the recordset list request across all zones. +func ListAll(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { + url := listAllRecordSetsURL(client) + if opts != nil { + query, err := opts.ToRecordSetListQuery() + if err != nil { + return pagination.Pager{Err: err} + } + url += query + } + return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page { + return RecordSetPage{pagination.LinkedPageBase{PageResult: r}} + }) +} + // Get implements the recordset Get request. func Get(ctx context.Context, client *gophercloud.ServiceClient, zoneID string, rrsetID string) (r GetResult) { resp, err := client.Get(ctx, rrsetURL(client, zoneID, rrsetID), &r.Body, nil) @@ -155,7 +170,7 @@ func (opts UpdateOpts) ToRecordSetUpdateMap() (map[string]any, error) { return b, nil } -// Update updates a recordset in a given zone +// Update updates a recordset in a given zone. func Update(ctx context.Context, client *gophercloud.ServiceClient, zoneID string, rrsetID string, opts UpdateOptsBuilder) (r UpdateResult) { b, err := opts.ToRecordSetUpdateMap() if err != nil { diff --git a/openstack/dns/v2/recordsets/testing/fixtures_test.go b/openstack/dns/v2/recordsets/testing/fixtures_test.go index 42a6c0d6e5..037f3d374d 100644 --- a/openstack/dns/v2/recordsets/testing/fixtures_test.go +++ b/openstack/dns/v2/recordsets/testing/fixtures_test.go @@ -199,23 +199,34 @@ var ExpectedRecordSetSlice = []recordsets.RecordSet{FirstRecordSet, SecondRecord // from ListByZoneOutput. var ExpectedRecordSetSliceLimited = []recordsets.RecordSet{SecondRecordSet} +func handleListSuccessfully(t *testing.T, w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + w.Header().Add("Content-Type", "application/json") + if err := r.ParseForm(); err != nil { + t.Errorf("Failed to parse request form %v", err) + } + marker := r.Form.Get("marker") + switch marker { + case "f7b10e9b-0cae-4a91-b162-562bc6096648": + fmt.Fprint(w, ListByZoneOutputLimited) + case "": + fmt.Fprint(w, ListByZoneOutput) + } +} + // HandleListByZoneSuccessfully configures the test server to respond to a ListByZone request. func HandleListByZoneSuccessfully(t *testing.T, fakeServer th.FakeServer) { fakeServer.Mux.HandleFunc("/zones/2150b1bf-dee2-4221-9d85-11f7886fb15f/recordsets", func(w http.ResponseWriter, r *http.Request) { - th.TestMethod(t, r, "GET") - th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + handleListSuccessfully(t, w, r) + }) +} - w.Header().Add("Content-Type", "application/json") - if err := r.ParseForm(); err != nil { - t.Errorf("Failed to parse request form %v", err) - } - marker := r.Form.Get("marker") - switch marker { - case "f7b10e9b-0cae-4a91-b162-562bc6096648": - fmt.Fprint(w, ListByZoneOutputLimited) - case "": - fmt.Fprint(w, ListByZoneOutput) - } +// HandleListAllSuccessfully configures the test server to respond to a ListAll request. +func HandleListAllSuccessfully(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/recordsets", func(w http.ResponseWriter, r *http.Request) { + handleListSuccessfully(t, w, r) }) } diff --git a/openstack/dns/v2/recordsets/testing/requests_test.go b/openstack/dns/v2/recordsets/testing/requests_test.go index a2b083fc3c..a28518702b 100644 --- a/openstack/dns/v2/recordsets/testing/requests_test.go +++ b/openstack/dns/v2/recordsets/testing/requests_test.go @@ -63,6 +63,58 @@ func TestListByZoneAllPages(t *testing.T) { th.CheckEquals(t, 2, len(allRecordSets)) } +func TestListAll(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + HandleListAllSuccessfully(t, fakeServer) + + count := 0 + err := recordsets.ListAll(client.ServiceClient(fakeServer), nil).EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) { + count++ + actual, err := recordsets.ExtractRecordSets(page) + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, ExpectedRecordSetSlice, actual) + + return true, nil + }) + th.AssertNoErr(t, err) + th.CheckEquals(t, 1, count) +} + +func TestListAllLimited(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + HandleListAllSuccessfully(t, fakeServer) + + count := 0 + listOpts := recordsets.ListOpts{ + Limit: 1, + Marker: "f7b10e9b-0cae-4a91-b162-562bc6096648", + } + err := recordsets.ListAll(client.ServiceClient(fakeServer), listOpts).EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) { + count++ + actual, err := recordsets.ExtractRecordSets(page) + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, ExpectedRecordSetSliceLimited, actual) + + return true, nil + }) + th.AssertNoErr(t, err) + th.CheckEquals(t, 1, count) +} + +func TestListAllPages(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + HandleListAllSuccessfully(t, fakeServer) + + allPages, err := recordsets.ListAll(client.ServiceClient(fakeServer), nil).AllPages(context.TODO()) + th.AssertNoErr(t, err) + allRecordSets, err := recordsets.ExtractRecordSets(allPages) + th.AssertNoErr(t, err) + th.CheckEquals(t, 2, len(allRecordSets)) +} + func TestGet(t *testing.T) { fakeServer := th.SetupHTTP() defer fakeServer.Teardown() diff --git a/openstack/dns/v2/recordsets/urls.go b/openstack/dns/v2/recordsets/urls.go index 26d9384aa0..8e539d2311 100644 --- a/openstack/dns/v2/recordsets/urls.go +++ b/openstack/dns/v2/recordsets/urls.go @@ -6,6 +6,10 @@ func baseURL(c *gophercloud.ServiceClient, zoneID string) string { return c.ServiceURL("zones", zoneID, "recordsets") } +func listAllRecordSetsURL(c *gophercloud.ServiceClient) string { + return c.ServiceURL("recordsets") +} + func rrsetURL(c *gophercloud.ServiceClient, zoneID string, rrsetID string) string { return c.ServiceURL("zones", zoneID, "recordsets", rrsetID) } From 63e76ea010ad27da30b1b20c9ca355e735f1d8fa Mon Sep 17 00:00:00 2001 From: root Date: Fri, 15 May 2026 06:52:50 -0700 Subject: [PATCH 406/429] add support for portforwarding ranges --- .../networking/v2/extensions/layer3/layer3.go | 29 +++ .../extensions/layer3/portforwardings_test.go | 37 ++++ .../extensions/layer3/portforwarding/doc.go | 16 ++ .../layer3/portforwarding/requests.go | 12 +- .../layer3/portforwarding/results.go | 7 + .../portforwarding/testing/fixtures_test.go | 12 +- .../portforwarding/testing/requests_test.go | 180 +++++++++++++++++- 7 files changed, 279 insertions(+), 14 deletions(-) diff --git a/internal/acceptance/openstack/networking/v2/extensions/layer3/layer3.go b/internal/acceptance/openstack/networking/v2/extensions/layer3/layer3.go index c45bb08069..52d91c0118 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/layer3/layer3.go +++ b/internal/acceptance/openstack/networking/v2/extensions/layer3/layer3.go @@ -97,6 +97,35 @@ func CreatePortForwarding(t *testing.T, client *gophercloud.ServiceClient, fipID return pf, err } +// CreatePortRangeForwarding creates a port range forwarding for a given floating IP +// and port. An error will be returned if the creation failed. +func CreatePortRangeForwarding(t *testing.T, client *gophercloud.ServiceClient, fipID string, portID string, portFixedIPs []ports.IP) (*portforwarding.PortForwarding, error) { + t.Logf("Attempting to create Port Range forwarding for floating IP with ID: %s", fipID) + + fixedIP := portFixedIPs[0] + internalIP := fixedIP.IPAddress + pfDescription := "Test description range" + createOpts := &portforwarding.CreateOpts{ + Description: pfDescription, + Protocol: "tcp", + InternalPortRange: "1200:1299", + ExternalPortRange: "1200:1299", + InternalIPAddress: internalIP, + InternalPortID: portID, + } + + pf, err := portforwarding.Create(context.TODO(), client, fipID, createOpts).Extract() + if err != nil { + return pf, err + } + + t.Logf("Created Port Range Forwarding.") + + th.AssertEquals(t, pf.Protocol, "tcp") + + return pf, err +} + // DeletePortForwarding deletes a Port Forwarding with a given ID and a given floating IP ID. // A fatal error is returned if the deletion fails. Works best as a deferred function func DeletePortForwarding(t *testing.T, client *gophercloud.ServiceClient, fipID string, pfID string) { diff --git a/internal/acceptance/openstack/networking/v2/extensions/layer3/portforwardings_test.go b/internal/acceptance/openstack/networking/v2/extensions/layer3/portforwardings_test.go index 6811d472f7..e6ba659068 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/layer3/portforwardings_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/layer3/portforwardings_test.go @@ -60,6 +60,13 @@ func TestLayer3PortForwardingsCreateDelete(t *testing.T) { defer DeletePortForwarding(t, client, fip.ID, pf.ID) tools.PrintResource(t, pf) + pfRange, err := CreatePortRangeForwarding(t, client, fip.ID, port.ID, port.FixedIPs) + th.AssertNoErr(t, err) + th.AssertEquals(t, pfRange.Description, "Test description range") + defer DeletePortForwarding(t, client, fip.ID, pfRange.ID) + tools.PrintResource(t, pfRange) + + // Test updating port newPf, err := portforwarding.Get(context.TODO(), client, fip.ID, pf.ID).Extract() th.AssertNoErr(t, err) @@ -77,6 +84,27 @@ func TestLayer3PortForwardingsCreateDelete(t *testing.T) { th.AssertNoErr(t, err) th.AssertEquals(t, newPf.Description, "") + // Test updating port range + newRangePf, err := portforwarding.Get(context.TODO(), client, fip.ID, pfRange.ID).Extract() + th.AssertNoErr(t, err) + + updateOpts = portforwarding.UpdateOpts{ + Description: new(string), + Protocol: "tcp", + InternalPortRange: "1300:1399", + ExternalPortRange: "1300:1399", + } + + _, err = portforwarding.Update(context.TODO(), client, fip.ID, newRangePf.ID, updateOpts).Extract() + th.AssertNoErr(t, err) + + newRangePf, err = portforwarding.Get(context.TODO(), client, fip.ID, pfRange.ID).Extract() + th.AssertNoErr(t, err) + th.AssertEquals(t, newRangePf.Description, "") + th.AssertEquals(t, newRangePf.Protocol, "tcp") + th.AssertEquals(t, newRangePf.InternalPortRange, "1300:1399") + th.AssertEquals(t, newRangePf.ExternalPortRange, "1300:1399") + allPages, err := portforwarding.List(client, portforwarding.ListOpts{}, fip.ID).AllPages(context.TODO()) th.AssertNoErr(t, err) @@ -92,4 +120,13 @@ func TestLayer3PortForwardingsCreateDelete(t *testing.T) { th.AssertEquals(t, true, found) + found = false + for _, pf := range allPFs { + if pf.ID == newRangePf.ID { + found = true + } + } + + th.AssertEquals(t, true, found) + } diff --git a/openstack/networking/v2/extensions/layer3/portforwarding/doc.go b/openstack/networking/v2/extensions/layer3/portforwarding/doc.go index bf67b92b6b..b010f62177 100644 --- a/openstack/networking/v2/extensions/layer3/portforwarding/doc.go +++ b/openstack/networking/v2/extensions/layer3/portforwarding/doc.go @@ -44,6 +44,22 @@ Example to Create a Port Forwarding for a floating IP panic(err) } +or, for port ranges + + createOpts := &portforwarding.CreateOpts{ + Protocol: "tcp", + InternalPortRange: "100:199", + ExternalPortRange: "1500:1599", + InternalIPAddress: internalIP, + InternalPortID: portID, + } + + pf, err := portforwarding.Create(context.TODO(), networkingClient, floatingIPID, createOpts).Extract() + + if err != nil { + panic(err) + } + Example to Update a Port Forwarding updateOpts := portforwarding.UpdateOpts{ diff --git a/openstack/networking/v2/extensions/layer3/portforwarding/requests.go b/openstack/networking/v2/extensions/layer3/portforwarding/requests.go index 1b07b6b7c9..49b7842389 100644 --- a/openstack/networking/v2/extensions/layer3/portforwarding/requests.go +++ b/openstack/networking/v2/extensions/layer3/portforwarding/requests.go @@ -21,6 +21,7 @@ type ListOpts struct { Description string `q:"description"` InternalPortID string `q:"internal_port_id"` ExternalPort string `q:"external_port"` + ExternalPortRange string `q:"external_port_range"` InternalIPAddress string `q:"internal_ip_address"` Protocol string `q:"protocol"` InternalPort string `q:"internal_port"` @@ -62,13 +63,15 @@ func Get(ctx context.Context, c *gophercloud.ServiceClient, floatingIpId string, } // CreateOpts contains all the values needed to create a new port forwarding -// resource. All attributes are required. +// resource. Internal/External ports and port ranges are mutually exclusive. type CreateOpts struct { Description string `json:"description,omitempty"` InternalPortID string `json:"internal_port_id"` InternalIPAddress string `json:"internal_ip_address"` - InternalPort int `json:"internal_port"` - ExternalPort int `json:"external_port"` + InternalPort int `json:"internal_port,omitempty"` + InternalPortRange string `json:"internal_port_range,omitempty"` + ExternalPort int `json:"external_port,omitempty"` + ExternalPortRange string `json:"external_port_range,omitempty"` Protocol string `json:"protocol"` } @@ -98,12 +101,15 @@ func Create(ctx context.Context, c *gophercloud.ServiceClient, floatingIpId stri } // UpdateOpts contains the values used when updating a port forwarding resource. +// Only Internal/External port values OR range values should be specified, not both or mixed. type UpdateOpts struct { Description *string `json:"description,omitempty"` InternalPortID string `json:"internal_port_id,omitempty"` InternalIPAddress string `json:"internal_ip_address,omitempty"` InternalPort int `json:"internal_port,omitempty"` + InternalPortRange string `json:"internal_port_range,omitempty"` ExternalPort int `json:"external_port,omitempty"` + ExternalPortRange string `json:"external_port_range,omitempty"` Protocol string `json:"protocol,omitempty"` } diff --git a/openstack/networking/v2/extensions/layer3/portforwarding/results.go b/openstack/networking/v2/extensions/layer3/portforwarding/results.go index 632cfa9ba9..0c31b84528 100644 --- a/openstack/networking/v2/extensions/layer3/portforwarding/results.go +++ b/openstack/networking/v2/extensions/layer3/portforwarding/results.go @@ -19,6 +19,9 @@ type PortForwarding struct { // The TCP/UDP/other protocol port number of the port forwarding’s floating IP address. ExternalPort int `json:"external_port"` + // The TCP/UDP/other protocol port range of the port forwarding’s floating IP address. + ExternalPortRange string `json:"external_port_range"` + // The IP protocol used in the floating IP port forwarding. Protocol string `json:"protocol"` @@ -26,6 +29,10 @@ type PortForwarding struct { // IP address associated to the floating ip port forwarding. InternalPort int `json:"internal_port"` + // The TCP/UDP/other protocol port range of the Neutron port fixed + // IP address associated to the floating ip port forwarding. + InternalPortRange string `json:"internal_port_range"` + // The fixed IPv4 address of the Neutron port associated // to the floating IP port forwarding. InternalIPAddress string `json:"internal_ip_address"` diff --git a/openstack/networking/v2/extensions/layer3/portforwarding/testing/fixtures_test.go b/openstack/networking/v2/extensions/layer3/portforwarding/testing/fixtures_test.go index b9362c4859..d479e0577f 100644 --- a/openstack/networking/v2/extensions/layer3/portforwarding/testing/fixtures_test.go +++ b/openstack/networking/v2/extensions/layer3/portforwarding/testing/fixtures_test.go @@ -20,11 +20,21 @@ const PoFw_second = `{ "id": "e0a0274e-4d19-4eab-9e12-9e77a8caf3ea" }` +const PoFw_third = `{ + "protocol": "tcp", + "internal_ip_address": "10.0.0.19", + "internal_port_range": "1200:1299", + "internal_port_id": "dba563d2-aa9e-4a21-8cc2-3e0bdec9015a", + "external_port_range": "1100:1199", + "id": "f3a9f921-6bed-492b-a3fa-32a76fdd0159" + }` + var ListResponse = fmt.Sprintf(` { "port_forwardings": [ %s, +%s, %s ] } -`, PoFw, PoFw_second) +`, PoFw, PoFw_second, PoFw_third) diff --git a/openstack/networking/v2/extensions/layer3/portforwarding/testing/requests_test.go b/openstack/networking/v2/extensions/layer3/portforwarding/testing/requests_test.go index 57f7fce6c8..384354c3f5 100644 --- a/openstack/networking/v2/extensions/layer3/portforwarding/testing/requests_test.go +++ b/openstack/networking/v2/extensions/layer3/portforwarding/testing/requests_test.go @@ -53,6 +53,14 @@ func TestPortForwardingList(t *testing.T) { ExternalPort: 2230, ID: "e0a0274e-4d19-4eab-9e12-9e77a8caf3ea", }, + { + Protocol: "tcp", + InternalIPAddress: "10.0.0.19", + InternalPortRange: "1200:1299", + InternalPortID: "dba563d2-aa9e-4a21-8cc2-3e0bdec9015a", + ExternalPortRange: "1100:1199", + ID: "f3a9f921-6bed-492b-a3fa-32a76fdd0159", + }, } th.CheckDeepEquals(t, expected, actual) @@ -77,7 +85,7 @@ func TestCreate(t *testing.T) { th.TestHeader(t, r, "Accept", "application/json") th.TestJSONRequest(t, r, ` { - "port_forwarding": { + "port_forwarding": { "protocol": "tcp", "internal_ip_address": "10.0.0.11", "internal_port": 25, @@ -85,21 +93,20 @@ func TestCreate(t *testing.T) { "external_port": 2230 } } - - `) +`) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) fmt.Fprint(w, ` { - "port_forwarding": { - "protocol": "tcp", - "internal_ip_address": "10.0.0.11", - "internal_port": 25, - "internal_port_id": "1238be08-a2a8-4b8d-addf-fb5e2250e480", - "external_port": 2230, - "id": "725ade3c-9760-4880-8080-8fc2dbab9acc" + "port_forwarding": { + "protocol": "tcp", + "internal_ip_address": "10.0.0.11", + "internal_port": 25, + "internal_port_id": "1238be08-a2a8-4b8d-addf-fb5e2250e480", + "external_port": 2230, + "id": "725ade3c-9760-4880-8080-8fc2dbab9acc" } }`) }) @@ -123,6 +130,62 @@ func TestCreate(t *testing.T) { th.AssertEquals(t, "tcp", pf.Protocol) } +func TestCreateRange(t *testing.T) { + // Test port range + fakeServerRange := th.SetupHTTP() + defer fakeServerRange.Teardown() + fakeServerRange.Mux.HandleFunc("/v2.0/floatingips/f40600c2-f240-4bb0-aa76-f6f18b2aaab1/port_forwardings", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "POST") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestJSONRequest(t, r, ` +{ + "port_forwarding": { + "protocol": "tcp", + "internal_ip_address": "10.0.0.19", + "internal_port_range": "1200:1299", + "internal_port_id": "dba563d2-aa9e-4a21-8cc2-3e0bdec9015a", + "external_port_range": "1100:1199" + } +} +`) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + + fmt.Fprint(w, ` +{ + "port_forwarding": { + "protocol": "tcp", + "internal_ip_address": "10.0.0.19", + "internal_port_range": "1200:1299", + "internal_port_id": "dba563d2-aa9e-4a21-8cc2-3e0bdec9015a", + "external_port_range": "1100:1199", + "id": "f3a9f921-6bed-492b-a3fa-32a76fdd0159" + } +}`) + }) + + options := portforwarding.CreateOpts{ + Protocol: "tcp", + InternalIPAddress: "10.0.0.19", + InternalPortRange: "1200:1299", + ExternalPortRange: "1100:1199", + InternalPortID: "dba563d2-aa9e-4a21-8cc2-3e0bdec9015a", + } + + pf, err := portforwarding.Create(context.TODO(), fake.ServiceClient(fakeServerRange), "f40600c2-f240-4bb0-aa76-f6f18b2aaab1", options).Extract() + th.AssertNoErr(t, err) + + th.AssertEquals(t, "f3a9f921-6bed-492b-a3fa-32a76fdd0159", pf.ID) + th.AssertEquals(t, "10.0.0.19", pf.InternalIPAddress) + th.AssertEquals(t, "1200:1299", pf.InternalPortRange) + th.AssertEquals(t, "dba563d2-aa9e-4a21-8cc2-3e0bdec9015a", pf.InternalPortID) + th.AssertEquals(t, "1100:1199", pf.ExternalPortRange) + th.AssertEquals(t, "tcp", pf.Protocol) +} + func TestGet(t *testing.T) { fakeServer := th.SetupHTTP() defer fakeServer.Teardown() @@ -159,6 +222,42 @@ func TestGet(t *testing.T) { th.AssertEquals(t, 2230, pf.ExternalPort) } +func TestGetRange(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + fakeServer.Mux.HandleFunc("/v2.0/floatingips/2f245a7b-796b-4f26-9cf9-9e82d248fda7/port_forwardings/725ade3c-9760-4880-8080-8fc2dbab9acc", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, ` +{ + "port_forwarding": { + "protocol": "tcp", + "internal_ip_address": "10.0.0.11", + "internal_port_range": "1200:1299", + "internal_port_id": "1238be08-a2a8-4b8d-addf-fb5e2250e480", + "external_port_range": "1100:1199", + "id": "725ade3c-9760-4880-8080-8fc2dbab9acc" + } +} + `) + }) + + pf, err := portforwarding.Get(context.TODO(), fake.ServiceClient(fakeServer), "2f245a7b-796b-4f26-9cf9-9e82d248fda7", "725ade3c-9760-4880-8080-8fc2dbab9acc").Extract() + th.AssertNoErr(t, err) + + th.AssertEquals(t, "tcp", pf.Protocol) + th.AssertEquals(t, "725ade3c-9760-4880-8080-8fc2dbab9acc", pf.ID) + th.AssertEquals(t, "10.0.0.11", pf.InternalIPAddress) + th.AssertEquals(t, "1200:1299", pf.InternalPortRange) + th.AssertEquals(t, "1238be08-a2a8-4b8d-addf-fb5e2250e480", pf.InternalPortID) + th.AssertEquals(t, "1100:1199", pf.ExternalPortRange) +} + func TestDelete(t *testing.T) { fakeServer := th.SetupHTTP() defer fakeServer.Teardown() @@ -233,3 +332,64 @@ func TestUpdate(t *testing.T) { } th.AssertDeepEquals(t, expected, *actual) } + +func TestUpdateRange(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + + fakeServer.Mux.HandleFunc("/v2.0/floatingips/2f245a7b-796b-4f26-9cf9-9e82d248fda7/port_forwardings/f3a9f921-6bed-492b-a3fa-32a76fdd0159", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "PUT") + th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) + th.TestHeader(t, r, "Content-Type", "application/json") + th.TestHeader(t, r, "Accept", "application/json") + th.TestJSONRequest(t, r, ` +{ + "port_forwarding": { + "protocol": "udp", + "internal_port_range": "1500:1599", + "internal_port_id": "99889dc2-19a7-4edb-b9d0-d2ace8d1e144", + "external_port_range": "23000:23099" + } +} +`) + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + fmt.Fprint(w, ` +{ + "port_forwarding": { + "protocol": "udp", + "internal_ip_address": "10.0.0.14", + "internal_port_range": "1500:1599", + "internal_port_id": "99889dc2-19a7-4edb-b9d0-d2ace8d1e144", + "external_port_range": "23000:23099", + "id": "f3a9f921-6bed-492b-a3fa-32a76fdd0159" + } +} +`) + }) + + updatedProtocol := "udp" + updatedInternalPortRange := "1500:1599" + updatedInternalPortID := "99889dc2-19a7-4edb-b9d0-d2ace8d1e144" + updatedExternalPortRange := "23000:23099" + options := portforwarding.UpdateOpts{ + Protocol: updatedProtocol, + InternalPortRange: updatedInternalPortRange, + InternalPortID: updatedInternalPortID, + ExternalPortRange: updatedExternalPortRange, + } + + actual, err := portforwarding.Update(context.TODO(), fake.ServiceClient(fakeServer), "2f245a7b-796b-4f26-9cf9-9e82d248fda7", "f3a9f921-6bed-492b-a3fa-32a76fdd0159", options).Extract() + th.AssertNoErr(t, err) + expected := portforwarding.PortForwarding{ + Protocol: "udp", + InternalIPAddress: "10.0.0.14", + InternalPortRange: "1500:1599", + ID: "f3a9f921-6bed-492b-a3fa-32a76fdd0159", + InternalPortID: "99889dc2-19a7-4edb-b9d0-d2ace8d1e144", + ExternalPortRange: "23000:23099", + } + th.AssertDeepEquals(t, expected, *actual) +} From bba59193b11a451c06116657d7a6486c598cef7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Thu, 28 May 2026 11:27:08 +0200 Subject: [PATCH 407/429] Fix assertion argument order: expected first, actual second All equality assertion helpers (AssertEquals, CheckEquals, AssertDeepEquals, CheckDeepEquals, etc.) expect (t, expected, actual) but many call sites had the arguments swapped, putting the actual value first and the expected literal second. This causes confusing error messages on test failure. --- .../.template/testing/requests_test.go | 2 +- .../baremetal/httpbasic/allocations_test.go | 2 +- .../baremetal/httpbasic/nodes_test.go | 8 +- .../baremetal/httpbasic/ports_test.go | 4 +- .../baremetal/noauth/allocations_test.go | 2 +- .../openstack/baremetal/noauth/nodes_test.go | 4 +- .../openstack/baremetal/noauth/ports_test.go | 4 +- .../baremetal/v1/allocations_test.go | 2 +- .../openstack/baremetal/v1/nodes_test.go | 16 +- .../openstack/baremetal/v1/ports_test.go | 4 +- .../openstack/blockstorage/v2/backups_test.go | 2 +- .../openstack/blockstorage/v2/blockstorage.go | 4 +- .../blockstorage/v2/snapshots_test.go | 2 +- .../openstack/blockstorage/v2/volumes_test.go | 2 +- .../openstack/blockstorage/v3/backups_test.go | 2 +- .../openstack/blockstorage/v3/blockstorage.go | 16 +- .../openstack/blockstorage/v3/qos_test.go | 2 +- .../blockstorage/v3/quotaset_test.go | 2 +- .../blockstorage/v3/snapshots_test.go | 4 +- .../openstack/blockstorage/v3/volumes_test.go | 4 +- .../blockstorage/v3/volumetypes_test.go | 20 +- .../openstack/compute/v2/aggregates_test.go | 6 +- .../openstack/container/v1/capsules_test.go | 4 +- .../containerinfra/v1/clusters_test.go | 6 +- .../v1/clustertemplates_test.go | 2 +- internal/acceptance/openstack/dns/v2/dns.go | 6 +- .../openstack/dns/v2/recordsets_test.go | 10 +- .../openstack/dns/v2/transfers_test.go | 4 +- .../openstack/dns/v2/tsigkeys_test.go | 4 +- .../acceptance/openstack/dns/v2/zones_test.go | 2 +- .../openstack/identity/v2/extension_test.go | 2 +- .../openstack/identity/v2/role_test.go | 4 +- .../openstack/identity/v2/tenant_test.go | 2 +- .../openstack/identity/v2/user_test.go | 2 +- .../v3/applicationcredentials_test.go | 16 +- .../openstack/identity/v3/domains_test.go | 4 +- .../openstack/identity/v3/endpoint_test.go | 8 +- .../openstack/identity/v3/groups_test.go | 6 +- .../openstack/identity/v3/oauth1_test.go | 4 +- .../openstack/identity/v3/projects_test.go | 26 +- .../openstack/identity/v3/roles_test.go | 26 +- .../openstack/identity/v3/service_test.go | 4 +- .../openstack/identity/v3/trusts_test.go | 4 +- .../openstack/identity/v3/users_test.go | 16 +- .../openstack/image/v2/images_test.go | 6 +- .../openstack/image/v2/imageservice.go | 4 +- .../openstack/keymanager/v1/acls_test.go | 16 +- .../keymanager/v1/containers_test.go | 8 +- .../openstack/keymanager/v1/keymanager.go | 24 +- .../openstack/keymanager/v1/orders_test.go | 2 +- .../openstack/keymanager/v1/secrets_test.go | 32 +- .../openstack/loadbalancer/v2/loadbalancer.go | 38 +-- .../loadbalancer/v2/loadbalancers_test.go | 2 +- .../openstack/metric/v1/metrics_test.go | 2 +- .../bgp/speakers/bgpspeakers_test.go | 2 +- .../v2/extensions/fwaas_v2/fwaas_v2.go | 2 +- .../v2/extensions/fwaas_v2/groups_test.go | 6 +- .../v2/extensions/fwaas_v2/policy_test.go | 4 +- .../v2/extensions/fwaas_v2/rule_test.go | 2 +- .../extensions/layer3/addressscopes_test.go | 2 +- .../v2/extensions/layer3/floatingips_test.go | 4 +- .../extensions/layer3/l3_scheduling_test.go | 4 +- .../networking/v2/extensions/layer3/layer3.go | 4 +- .../extensions/layer3/portforwardings_test.go | 14 +- .../v2/extensions/layer3/routers_test.go | 6 +- .../extensions/qos/policies/policies_test.go | 2 +- .../v2/extensions/qos/rules/rules_test.go | 12 +- .../networking/v2/extensions/security_test.go | 8 +- .../v2/extensions/segments/segments.go | 2 +- .../subnetpools/subnetpools_test.go | 2 +- .../vlantransparent/vlantransparent_test.go | 2 +- .../openstack/networking/v2/networking.go | 2 +- .../openstack/networking/v2/networks_test.go | 6 +- .../openstack/networking/v2/ports_test.go | 2 +- .../openstack/networking/v2/subnets_test.go | 6 +- .../objectstorage/v1/objects_test.go | 2 +- .../orchestration/v1/stackevents_test.go | 2 +- .../orchestration/v1/stackresources_test.go | 2 +- .../openstack/orchestration/v1/stacks_test.go | 2 +- .../sharedfilesystems/v2/services_test.go | 2 +- .../v2/sharetransfers_test.go | 4 +- .../v1/conductors/testing/requests_test.go | 2 +- .../v1/nodes/testing/requests_test.go | 6 +- .../v1/ports/testing/requests_test.go | 2 +- .../v1/introspection/testing/results_test.go | 2 +- .../v2/backups/testing/requests_test.go | 20 +- .../v2/snapshots/testing/requests_test.go | 10 +- .../v2/transfers/testing/requests_test.go | 2 +- .../v2/volumes/testing/requests_test.go | 8 +- .../v3/backups/testing/requests_test.go | 20 +- .../testing/requests_test.go | 16 +- .../v3/snapshots/testing/requests_test.go | 10 +- .../v3/transfers/testing/requests_test.go | 2 +- .../v3/volumes/testing/requests_test.go | 14 +- .../v3/volumetypes/testing/requests_test.go | 24 +- .../apiversions/testing/requests_test.go | 2 +- .../v2/extensions/testing/delegate_test.go | 10 +- .../v2/keypairs/testing/fixtures_test.go | 2 +- .../remoteconsoles/testing/requests_test.go | 2 +- .../v2/servers/testing/results_test.go | 2 +- .../compute/v2/usage/testing/requests_test.go | 4 +- .../configurations/testing/requests_test.go | 2 +- .../dns/v2/zones/testing/requests_test.go | 6 +- .../v2/tenants/testing/requests_test.go | 2 +- .../testing/requests_test.go | 8 +- .../v3/catalog/testing/catalog_test.go | 2 +- .../v3/credentials/testing/requests_test.go | 6 +- .../v3/domains/testing/requests_test.go | 4 +- .../ec2credentials/testing/requests_test.go | 2 +- .../v3/federation/testing/requests_test.go | 2 +- .../v3/groups/testing/requests_test.go | 8 +- .../v3/limits/testing/requests_test.go | 2 +- .../v3/oauth1/testing/requests_test.go | 6 +- .../v3/policies/testing/requests_test.go | 2 +- .../v3/projects/testing/requests_test.go | 6 +- .../v3/regions/testing/requests_test.go | 4 +- .../registeredlimits/testing/requests_test.go | 2 +- .../v3/roles/testing/requests_test.go | 18 +- .../v3/services/testing/requests_test.go | 10 +- .../v3/trusts/testing/requests_test.go | 4 +- .../v3/users/testing/requests_test.go | 8 +- .../v2/imageimport/testing/requests_test.go | 4 +- .../image/v2/tasks/testing/requests_test.go | 32 +- .../v1/containers/testing/requests_test.go | 4 +- .../v1/orders/testing/requests_test.go | 2 +- .../v1/secrets/testing/requests_test.go | 2 +- .../v2/loadbalancers/testing/requests_test.go | 2 +- .../v2/queues/testing/requests_test.go | 2 +- .../agents/testing/requests_test.go | 68 ++-- .../attributestags/testing/requests_test.go | 4 +- .../bgp/speakers/testing/requests_test.go | 6 +- .../extensions/dns/testing/fixtures_test.go | 6 +- .../extensions/dns/testing/requests_test.go | 72 ++-- .../fwaas_v2/groups/testing/requests_test.go | 8 +- .../addressscopes/testing/requests_test.go | 28 +- .../extraroutes/testing/requests_test.go | 8 +- .../layer3/routers/testing/requests_test.go | 46 +-- .../testing/requests_test.go | 16 +- .../portsbinding/testing/requests_test.go | 72 ++-- .../portstrustedvif/testing/requests_test.go | 72 ++-- .../provider/testing/results_test.go | 4 +- .../qos/policies/testing/requests_test.go | 52 +-- .../qos/rules/testing/requests_test.go | 16 +- .../rbacpolicies/testing/requests_test.go | 10 +- .../subnetpools/testing/requests_test.go | 62 ++-- .../v2/extensions/testing/delegate_test.go | 10 +- .../trunk_details/testing/requests_test.go | 12 +- .../trunks/testing/requests_test.go | 4 +- .../v2/networks/testing/requests_test.go | 56 ++-- .../v2/ports/testing/requests_test.go | 312 +++++++++--------- .../v2/subnets/testing/requests_test.go | 208 ++++++------ .../v2/subnets/testing/results_test.go | 4 +- .../v1/objects/testing/requests_test.go | 2 +- .../v1/stackevents/testing/requests_test.go | 4 +- .../stackresources/testing/requests_test.go | 2 +- .../v1/stacks/testing/requests_test.go | 2 +- .../orchestration/v1/stacks/utils_test.go | 2 +- .../apiversions/testing/requests_test.go | 4 +- .../v2/errors/testing/request_test.go | 6 +- .../v2/replicas/testing/request_test.go | 4 +- .../securityservices/testing/requests_test.go | 12 +- .../v2/sharenetworks/testing/requests_test.go | 10 +- .../v2/shares/testing/request_test.go | 40 +-- .../sharetransfers/testing/requests_test.go | 4 +- .../v2/sharetypes/testing/requests_test.go | 12 +- .../v2/snapshots/testing/request_test.go | 22 +- pagination/testing/marker_test.go | 2 +- testing/errors_test.go | 10 +- testing/provider_client_test.go | 12 +- testing/service_client_test.go | 2 +- 170 files changed, 1069 insertions(+), 1069 deletions(-) diff --git a/docs/contributor-tutorial/.template/testing/requests_test.go b/docs/contributor-tutorial/.template/testing/requests_test.go index f325d204de..9150678c7b 100644 --- a/docs/contributor-tutorial/.template/testing/requests_test.go +++ b/docs/contributor-tutorial/.template/testing/requests_test.go @@ -27,7 +27,7 @@ func TestListResources(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.AssertEquals(t, count, 1) + th.AssertEquals(t, 1, count) } func TestListResourcesAllPages(t *testing.T) { diff --git a/internal/acceptance/openstack/baremetal/httpbasic/allocations_test.go b/internal/acceptance/openstack/baremetal/httpbasic/allocations_test.go index faa667d05b..a34b606c5b 100644 --- a/internal/acceptance/openstack/baremetal/httpbasic/allocations_test.go +++ b/internal/acceptance/openstack/baremetal/httpbasic/allocations_test.go @@ -43,5 +43,5 @@ func TestAllocationsCreateDestroy(t *testing.T) { return false, nil }) th.AssertNoErr(t, err) - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } diff --git a/internal/acceptance/openstack/baremetal/httpbasic/nodes_test.go b/internal/acceptance/openstack/baremetal/httpbasic/nodes_test.go index a0c656d7f7..9727c6fc2a 100644 --- a/internal/acceptance/openstack/baremetal/httpbasic/nodes_test.go +++ b/internal/acceptance/openstack/baremetal/httpbasic/nodes_test.go @@ -44,7 +44,7 @@ func TestNodesCreateDestroy(t *testing.T) { }) th.AssertNoErr(t, err) - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestNodesUpdate(t *testing.T) { @@ -68,7 +68,7 @@ func TestNodesUpdate(t *testing.T) { }).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, updated.Maintenance, true) + th.AssertEquals(t, true, updated.Maintenance) } func TestNodesRAIDConfig(t *testing.T) { @@ -114,9 +114,9 @@ func TestNodesFirmwareInterface(t *testing.T) { th.AssertNoErr(t, err) defer v1.DeleteNode(t, client, node) - th.AssertEquals(t, node.FirmwareInterface, "no-firmware") + th.AssertEquals(t, "no-firmware", node.FirmwareInterface) nodeFirmwareCmps, err := nodes.ListFirmware(context.TODO(), client, node.UUID).Extract() th.AssertNoErr(t, err) - th.AssertDeepEquals(t, nodeFirmwareCmps, []nodes.FirmwareComponent{}) + th.AssertDeepEquals(t, []nodes.FirmwareComponent{}, nodeFirmwareCmps) } diff --git a/internal/acceptance/openstack/baremetal/httpbasic/ports_test.go b/internal/acceptance/openstack/baremetal/httpbasic/ports_test.go index 7773f8b23e..2c55bd3a08 100644 --- a/internal/acceptance/openstack/baremetal/httpbasic/ports_test.go +++ b/internal/acceptance/openstack/baremetal/httpbasic/ports_test.go @@ -47,7 +47,7 @@ func TestPortsCreateDestroy(t *testing.T) { }) th.AssertNoErr(t, err) - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestPortsUpdate(t *testing.T) { @@ -74,5 +74,5 @@ func TestPortsUpdate(t *testing.T) { }).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, updated.Address, "aa:bb:cc:dd:ee:ff") + th.AssertEquals(t, "aa:bb:cc:dd:ee:ff", updated.Address) } diff --git a/internal/acceptance/openstack/baremetal/noauth/allocations_test.go b/internal/acceptance/openstack/baremetal/noauth/allocations_test.go index d0b34737c5..bdd9902a19 100644 --- a/internal/acceptance/openstack/baremetal/noauth/allocations_test.go +++ b/internal/acceptance/openstack/baremetal/noauth/allocations_test.go @@ -43,5 +43,5 @@ func TestAllocationsCreateDestroy(t *testing.T) { return false, nil }) th.AssertNoErr(t, err) - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } diff --git a/internal/acceptance/openstack/baremetal/noauth/nodes_test.go b/internal/acceptance/openstack/baremetal/noauth/nodes_test.go index 64b9826a03..2b04459377 100644 --- a/internal/acceptance/openstack/baremetal/noauth/nodes_test.go +++ b/internal/acceptance/openstack/baremetal/noauth/nodes_test.go @@ -44,7 +44,7 @@ func TestNodesCreateDestroy(t *testing.T) { }) th.AssertNoErr(t, err) - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestNodesUpdate(t *testing.T) { @@ -68,7 +68,7 @@ func TestNodesUpdate(t *testing.T) { }).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, updated.Maintenance, true) + th.AssertEquals(t, true, updated.Maintenance) } func TestNodesRAIDConfig(t *testing.T) { diff --git a/internal/acceptance/openstack/baremetal/noauth/ports_test.go b/internal/acceptance/openstack/baremetal/noauth/ports_test.go index 3f10b3b85c..a3c419bf30 100644 --- a/internal/acceptance/openstack/baremetal/noauth/ports_test.go +++ b/internal/acceptance/openstack/baremetal/noauth/ports_test.go @@ -47,7 +47,7 @@ func TestPortsCreateDestroy(t *testing.T) { }) th.AssertNoErr(t, err) - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestPortsUpdate(t *testing.T) { @@ -74,5 +74,5 @@ func TestPortsUpdate(t *testing.T) { }).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, updated.Address, "aa:bb:cc:dd:ee:ff") + th.AssertEquals(t, "aa:bb:cc:dd:ee:ff", updated.Address) } diff --git a/internal/acceptance/openstack/baremetal/v1/allocations_test.go b/internal/acceptance/openstack/baremetal/v1/allocations_test.go index 6c2734f875..77f408c50a 100644 --- a/internal/acceptance/openstack/baremetal/v1/allocations_test.go +++ b/internal/acceptance/openstack/baremetal/v1/allocations_test.go @@ -41,5 +41,5 @@ func TestAllocationsCreateDestroy(t *testing.T) { return false, nil }) th.AssertNoErr(t, err) - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } diff --git a/internal/acceptance/openstack/baremetal/v1/nodes_test.go b/internal/acceptance/openstack/baremetal/v1/nodes_test.go index 87030a72e7..d35eff551a 100644 --- a/internal/acceptance/openstack/baremetal/v1/nodes_test.go +++ b/internal/acceptance/openstack/baremetal/v1/nodes_test.go @@ -42,7 +42,7 @@ func TestNodesCreateDestroy(t *testing.T) { return false, nil }) th.AssertNoErr(t, err) - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) th.AssertEquals(t, node.ProvisionState, string(nodes.Enroll)) @@ -110,7 +110,7 @@ func TestNodesUpdate(t *testing.T) { }).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, updated.Maintenance, true) + th.AssertEquals(t, true, updated.Maintenance) } func TestNodesMaintenance(t *testing.T) { @@ -132,8 +132,8 @@ func TestNodesMaintenance(t *testing.T) { updated, err := nodes.Get(context.TODO(), client, node.UUID).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, updated.Maintenance, true) - th.AssertEquals(t, updated.MaintenanceReason, "I'm tired") + th.AssertEquals(t, true, updated.Maintenance) + th.AssertEquals(t, "I'm tired", updated.MaintenanceReason) err = nodes.UnsetMaintenance(context.TODO(), client, node.UUID).ExtractErr() th.AssertNoErr(t, err) @@ -141,8 +141,8 @@ func TestNodesMaintenance(t *testing.T) { updated, err = nodes.Get(context.TODO(), client, node.UUID).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, updated.Maintenance, false) - th.AssertEquals(t, updated.MaintenanceReason, "") + th.AssertEquals(t, false, updated.Maintenance) + th.AssertEquals(t, "", updated.MaintenanceReason) } func TestNodesRAIDConfig(t *testing.T) { @@ -206,11 +206,11 @@ func TestNodesFirmwareInterface(t *testing.T) { th.AssertNoErr(t, err) defer DeleteNode(t, client, node) - th.AssertEquals(t, node.FirmwareInterface, "no-firmware") + th.AssertEquals(t, "no-firmware", node.FirmwareInterface) nodeFirmwareCmps, err := nodes.ListFirmware(context.TODO(), client, node.UUID).Extract() th.AssertNoErr(t, err) - th.AssertDeepEquals(t, nodeFirmwareCmps, []nodes.FirmwareComponent{}) + th.AssertDeepEquals(t, []nodes.FirmwareComponent{}, nodeFirmwareCmps) } func TestNodesVirtualMedia(t *testing.T) { diff --git a/internal/acceptance/openstack/baremetal/v1/ports_test.go b/internal/acceptance/openstack/baremetal/v1/ports_test.go index 783c0c556c..a28e49dba2 100644 --- a/internal/acceptance/openstack/baremetal/v1/ports_test.go +++ b/internal/acceptance/openstack/baremetal/v1/ports_test.go @@ -45,7 +45,7 @@ func TestPortsCreateDestroy(t *testing.T) { }) th.AssertNoErr(t, err) - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestPortsUpdate(t *testing.T) { @@ -71,5 +71,5 @@ func TestPortsUpdate(t *testing.T) { }).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, updated.Address, "aa:bb:cc:dd:ee:ff") + th.AssertEquals(t, "aa:bb:cc:dd:ee:ff", updated.Address) } diff --git a/internal/acceptance/openstack/blockstorage/v2/backups_test.go b/internal/acceptance/openstack/blockstorage/v2/backups_test.go index 00ade44bde..a01edb6612 100644 --- a/internal/acceptance/openstack/blockstorage/v2/backups_test.go +++ b/internal/acceptance/openstack/blockstorage/v2/backups_test.go @@ -39,7 +39,7 @@ func TestBackupsCRUD(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestBackupsResetStatus(t *testing.T) { diff --git a/internal/acceptance/openstack/blockstorage/v2/blockstorage.go b/internal/acceptance/openstack/blockstorage/v2/blockstorage.go index f920a615c1..c0d7effe10 100644 --- a/internal/acceptance/openstack/blockstorage/v2/blockstorage.go +++ b/internal/acceptance/openstack/blockstorage/v2/blockstorage.go @@ -82,7 +82,7 @@ func CreateVolume(t *testing.T, client *gophercloud.ServiceClient) (*volumes.Vol tools.PrintResource(t, volume) th.AssertEquals(t, volume.Name, volumeName) th.AssertEquals(t, volume.Description, volumeDescription) - th.AssertEquals(t, volume.Size, 1) + th.AssertEquals(t, 1, volume.Size) t.Logf("Successfully created volume: %s", volume.ID) @@ -125,7 +125,7 @@ func CreateVolumeFromImage(t *testing.T, client *gophercloud.ServiceClient) (*vo } th.AssertEquals(t, newVolume.Name, volumeName) - th.AssertEquals(t, newVolume.Size, 1) + th.AssertEquals(t, 1, newVolume.Size) t.Logf("Successfully created volume from image: %s", newVolume.ID) diff --git a/internal/acceptance/openstack/blockstorage/v2/snapshots_test.go b/internal/acceptance/openstack/blockstorage/v2/snapshots_test.go index 50ab203700..ec74ba0a4e 100644 --- a/internal/acceptance/openstack/blockstorage/v2/snapshots_test.go +++ b/internal/acceptance/openstack/blockstorage/v2/snapshots_test.go @@ -44,5 +44,5 @@ func TestSnapshots(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } diff --git a/internal/acceptance/openstack/blockstorage/v2/volumes_test.go b/internal/acceptance/openstack/blockstorage/v2/volumes_test.go index d54c6f8c5c..82dcabac28 100644 --- a/internal/acceptance/openstack/blockstorage/v2/volumes_test.go +++ b/internal/acceptance/openstack/blockstorage/v2/volumes_test.go @@ -57,7 +57,7 @@ func TestVolumesCreateDestroy(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestVolumesCreateForceDestroy(t *testing.T) { diff --git a/internal/acceptance/openstack/blockstorage/v3/backups_test.go b/internal/acceptance/openstack/blockstorage/v3/backups_test.go index 0050c551ab..eb67418fe3 100644 --- a/internal/acceptance/openstack/blockstorage/v3/backups_test.go +++ b/internal/acceptance/openstack/blockstorage/v3/backups_test.go @@ -37,7 +37,7 @@ func TestBackupsCRUD(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestBackupsResetStatus(t *testing.T) { diff --git a/internal/acceptance/openstack/blockstorage/v3/blockstorage.go b/internal/acceptance/openstack/blockstorage/v3/blockstorage.go index 782089963d..ebb9d59ed1 100644 --- a/internal/acceptance/openstack/blockstorage/v3/blockstorage.go +++ b/internal/acceptance/openstack/blockstorage/v3/blockstorage.go @@ -98,7 +98,7 @@ func CreateVolume(t *testing.T, client *gophercloud.ServiceClient) (*volumes.Vol tools.PrintResource(t, volume) th.AssertEquals(t, volume.Name, volumeName) th.AssertEquals(t, volume.Description, volumeDescription) - th.AssertEquals(t, volume.Size, 1) + th.AssertEquals(t, 1, volume.Size) t.Logf("Successfully created volume: %s", volume.ID) @@ -141,7 +141,7 @@ func CreateVolumeWithType(t *testing.T, client *gophercloud.ServiceClient, vt *v tools.PrintResource(t, volume) th.AssertEquals(t, volume.Name, volumeName) th.AssertEquals(t, volume.Description, volumeDescription) - th.AssertEquals(t, volume.Size, 1) + th.AssertEquals(t, 1, volume.Size) th.AssertEquals(t, volume.VolumeType, vt.Name) t.Logf("Successfully created volume: %s", volume.ID) @@ -168,7 +168,7 @@ func CreateVolumeType(t *testing.T, client *gophercloud.ServiceClient) (*volumet } tools.PrintResource(t, vt) - th.AssertEquals(t, vt.IsPublic, true) + th.AssertEquals(t, true, vt.IsPublic) th.AssertEquals(t, vt.Name, name) th.AssertEquals(t, vt.Description, description) // TODO: For some reason returned extra_specs are empty even in API reference: https://developer.openstack.org/api-ref/block-storage/v3/?expanded=create-a-volume-type-detail#volume-types-types @@ -201,7 +201,7 @@ func CreateVolumeTypeNoExtraSpecs(t *testing.T, client *gophercloud.ServiceClien } tools.PrintResource(t, vt) - th.AssertEquals(t, vt.IsPublic, true) + th.AssertEquals(t, true, vt.IsPublic) th.AssertEquals(t, vt.Name, name) th.AssertEquals(t, vt.Description, description) @@ -230,10 +230,10 @@ func CreateVolumeTypeMultiAttach(t *testing.T, client *gophercloud.ServiceClient } tools.PrintResource(t, vt) - th.AssertEquals(t, vt.IsPublic, true) + th.AssertEquals(t, true, vt.IsPublic) th.AssertEquals(t, vt.Name, name) th.AssertEquals(t, vt.Description, description) - th.AssertEquals(t, vt.ExtraSpecs["multiattach"], " True") + th.AssertEquals(t, " True", vt.ExtraSpecs["multiattach"]) t.Logf("Successfully created volume type: %s", vt.ID) @@ -262,7 +262,7 @@ func CreatePrivateVolumeType(t *testing.T, client *gophercloud.ServiceClient) (* } tools.PrintResource(t, vt) - th.AssertEquals(t, vt.IsPublic, false) + th.AssertEquals(t, false, vt.IsPublic) th.AssertEquals(t, vt.Name, name) th.AssertEquals(t, vt.Description, description) @@ -365,7 +365,7 @@ func CreateQoS(t *testing.T, client *gophercloud.ServiceClient) (*qos.QoS, error } tools.PrintResource(t, qs) - th.AssertEquals(t, qs.Consumer, "front-end") + th.AssertEquals(t, "front-end", qs.Consumer) th.AssertEquals(t, qs.Name, name) th.AssertDeepEquals(t, qs.Specs, createOpts.Specs) diff --git a/internal/acceptance/openstack/blockstorage/v3/qos_test.go b/internal/acceptance/openstack/blockstorage/v3/qos_test.go index 9c3d341cf1..686b472f58 100644 --- a/internal/acceptance/openstack/blockstorage/v3/qos_test.go +++ b/internal/acceptance/openstack/blockstorage/v3/qos_test.go @@ -68,7 +68,7 @@ func TestQoS(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) return true, nil }) diff --git a/internal/acceptance/openstack/blockstorage/v3/quotaset_test.go b/internal/acceptance/openstack/blockstorage/v3/quotaset_test.go index 125d9f9d6c..c87fce7e2f 100644 --- a/internal/acceptance/openstack/blockstorage/v3/quotaset_test.go +++ b/internal/acceptance/openstack/blockstorage/v3/quotaset_test.go @@ -130,7 +130,7 @@ func TestQuotasetUpdate(t *testing.T) { } } - th.AssertEquals(t, count, 3) + th.AssertEquals(t, 3, count) // unpopulate resultQuotas.Extra as it is different per cloud and test // rest of the quotaSet diff --git a/internal/acceptance/openstack/blockstorage/v3/snapshots_test.go b/internal/acceptance/openstack/blockstorage/v3/snapshots_test.go index 18f045fc30..047e72a7ad 100644 --- a/internal/acceptance/openstack/blockstorage/v3/snapshots_test.go +++ b/internal/acceptance/openstack/blockstorage/v3/snapshots_test.go @@ -69,7 +69,7 @@ func TestSnapshots(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) return true, nil }) @@ -87,7 +87,7 @@ func TestSnapshots(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) return true, nil }) diff --git a/internal/acceptance/openstack/blockstorage/v3/volumes_test.go b/internal/acceptance/openstack/blockstorage/v3/volumes_test.go index 5510a3cd92..7ca982f25a 100644 --- a/internal/acceptance/openstack/blockstorage/v3/volumes_test.go +++ b/internal/acceptance/openstack/blockstorage/v3/volumes_test.go @@ -60,7 +60,7 @@ func TestVolumes(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) return true, nil }) @@ -98,7 +98,7 @@ func TestVolumesMultiAttach(t *testing.T) { err = volumes.WaitForStatus(ctx, client, vol.ID, "available") th.AssertNoErr(t, err) - th.AssertEquals(t, vol.Multiattach, true) + th.AssertEquals(t, true, vol.Multiattach) } func TestVolumesCascadeDelete(t *testing.T) { diff --git a/internal/acceptance/openstack/blockstorage/v3/volumetypes_test.go b/internal/acceptance/openstack/blockstorage/v3/volumetypes_test.go index 7fa8457b19..41ad0091a2 100644 --- a/internal/acceptance/openstack/blockstorage/v3/volumetypes_test.go +++ b/internal/acceptance/openstack/blockstorage/v3/volumetypes_test.go @@ -38,7 +38,7 @@ func TestVolumeTypesCRUD(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) name := vt.Name + "-updated" description := vt.Description + "-updated" @@ -141,9 +141,9 @@ func TestVolumeTypesExtraSpecs(t *testing.T) { tools.PrintResource(t, createdExtraSpecs) - th.AssertEquals(t, len(createdExtraSpecs), 2) - th.AssertEquals(t, createdExtraSpecs["capabilities"], "gpu") - th.AssertEquals(t, createdExtraSpecs["volume_backend_name"], "ssd") + th.AssertEquals(t, 2, len(createdExtraSpecs)) + th.AssertEquals(t, "gpu", createdExtraSpecs["capabilities"]) + th.AssertEquals(t, "ssd", createdExtraSpecs["volume_backend_name"]) err = volumetypes.DeleteExtraSpec(context.TODO(), client, vt.ID, "volume_backend_name").ExtractErr() th.AssertNoErr(t, err) @@ -156,22 +156,22 @@ func TestVolumeTypesExtraSpecs(t *testing.T) { tools.PrintResource(t, updatedExtraSpec) - th.AssertEquals(t, updatedExtraSpec["capabilities"], "gpu-2") + th.AssertEquals(t, "gpu-2", updatedExtraSpec["capabilities"]) allExtraSpecs, err := volumetypes.ListExtraSpecs(context.TODO(), client, vt.ID).Extract() th.AssertNoErr(t, err) tools.PrintResource(t, allExtraSpecs) - th.AssertEquals(t, len(allExtraSpecs), 1) - th.AssertEquals(t, allExtraSpecs["capabilities"], "gpu-2") + th.AssertEquals(t, 1, len(allExtraSpecs)) + th.AssertEquals(t, "gpu-2", allExtraSpecs["capabilities"]) singleSpec, err := volumetypes.GetExtraSpec(context.TODO(), client, vt.ID, "capabilities").Extract() th.AssertNoErr(t, err) tools.PrintResource(t, singleSpec) - th.AssertEquals(t, singleSpec["capabilities"], "gpu-2") + th.AssertEquals(t, "gpu-2", singleSpec["capabilities"]) } func TestVolumeTypesAccess(t *testing.T) { @@ -206,7 +206,7 @@ func TestVolumeTypesAccess(t *testing.T) { tools.PrintResource(t, accessList) - th.AssertEquals(t, len(accessList), 1) + th.AssertEquals(t, 1, len(accessList)) th.AssertEquals(t, accessList[0].ProjectID, project.ID) th.AssertEquals(t, accessList[0].VolumeTypeID, vt.ID) @@ -225,7 +225,7 @@ func TestVolumeTypesAccess(t *testing.T) { tools.PrintResource(t, accessList) - th.AssertEquals(t, len(accessList), 0) + th.AssertEquals(t, 0, len(accessList)) } func TestEncryptionVolumeTypes(t *testing.T) { diff --git a/internal/acceptance/openstack/compute/v2/aggregates_test.go b/internal/acceptance/openstack/compute/v2/aggregates_test.go index bd376c295e..082cadd13c 100644 --- a/internal/acceptance/openstack/compute/v2/aggregates_test.go +++ b/internal/acceptance/openstack/compute/v2/aggregates_test.go @@ -57,8 +57,8 @@ func TestAggregatesCRUD(t *testing.T) { tools.PrintResource(t, aggregate) - th.AssertEquals(t, updatedAggregate.Name, "new_aggregate_name") - th.AssertEquals(t, updatedAggregate.AvailabilityZone, "new_azone") + th.AssertEquals(t, "new_aggregate_name", updatedAggregate.Name) + th.AssertEquals(t, "new_azone", updatedAggregate.AvailabilityZone) } func TestAggregatesAddRemoveHost(t *testing.T) { @@ -94,7 +94,7 @@ func TestAggregatesAddRemoveHost(t *testing.T) { tools.PrintResource(t, aggregateWithRemovedHost) - th.AssertEquals(t, len(aggregateWithRemovedHost.Hosts), 0) + th.AssertEquals(t, 0, len(aggregateWithRemovedHost.Hosts)) } func TestAggregatesSetRemoveMetadata(t *testing.T) { diff --git a/internal/acceptance/openstack/container/v1/capsules_test.go b/internal/acceptance/openstack/container/v1/capsules_test.go index 5da7010948..9873facf2c 100644 --- a/internal/acceptance/openstack/container/v1/capsules_test.go +++ b/internal/acceptance/openstack/container/v1/capsules_test.go @@ -52,7 +52,7 @@ func TestCapsuleBase(t *testing.T) { capsule, err := capsules.Get(context.TODO(), client, capsuleUUID).ExtractBase() th.AssertNoErr(t, err) - th.AssertEquals(t, capsule.MetaName, "template") + th.AssertEquals(t, "template", capsule.MetaName) err = capsules.Delete(context.TODO(), client, capsuleUUID).ExtractErr() th.AssertNoErr(t, err) @@ -105,7 +105,7 @@ func TestCapsuleV132(t *testing.T) { capsule, err := capsules.Get(context.TODO(), client, capsuleUUID).ExtractV132() th.AssertNoErr(t, err) - th.AssertEquals(t, capsule.MetaName, "template") + th.AssertEquals(t, "template", capsule.MetaName) err = capsules.Delete(context.TODO(), client, capsuleUUID).ExtractErr() th.AssertNoErr(t, err) diff --git a/internal/acceptance/openstack/containerinfra/v1/clusters_test.go b/internal/acceptance/openstack/containerinfra/v1/clusters_test.go index d12c31bf4a..a6ffbe5e42 100644 --- a/internal/acceptance/openstack/containerinfra/v1/clusters_test.go +++ b/internal/acceptance/openstack/containerinfra/v1/clusters_test.go @@ -39,7 +39,7 @@ func TestClustersCRUD(t *testing.T) { found = true } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) updateOpts := []clusters.UpdateOptsBuilder{ clusters.UpdateOpts{ Op: clusters.ReplaceOp, @@ -63,7 +63,7 @@ func TestClustersCRUD(t *testing.T) { newCluster, err := clusters.Get(context.TODO(), client, clusterID).Extract() th.AssertNoErr(t, err) th.AssertEquals(t, newCluster.UUID, clusterID) - th.AssertEquals(t, newCluster.MasterLBEnabled, false) + th.AssertEquals(t, false, newCluster.MasterLBEnabled) allPagesDetail, err := clusters.ListDetail(client, nil).AllPages(context.TODO()) th.AssertNoErr(t, err) @@ -77,7 +77,7 @@ func TestClustersCRUD(t *testing.T) { foundDetail = true } } - th.AssertEquals(t, foundDetail, true) + th.AssertEquals(t, true, foundDetail) tools.PrintResource(t, newCluster) } diff --git a/internal/acceptance/openstack/containerinfra/v1/clustertemplates_test.go b/internal/acceptance/openstack/containerinfra/v1/clustertemplates_test.go index fec59e8229..91bc67bd8f 100644 --- a/internal/acceptance/openstack/containerinfra/v1/clustertemplates_test.go +++ b/internal/acceptance/openstack/containerinfra/v1/clustertemplates_test.go @@ -36,7 +36,7 @@ func TestClusterTemplatesCRUD(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) template, err := clustertemplates.Get(context.TODO(), client, clusterTemplate.UUID).Extract() th.AssertNoErr(t, err) diff --git a/internal/acceptance/openstack/dns/v2/dns.go b/internal/acceptance/openstack/dns/v2/dns.go index 596ce75431..42e431b3cb 100644 --- a/internal/acceptance/openstack/dns/v2/dns.go +++ b/internal/acceptance/openstack/dns/v2/dns.go @@ -79,7 +79,7 @@ func CreateZone(t *testing.T, client *gophercloud.ServiceClient) (*zones.Zone, e t.Logf("Created Zone: %s", zoneName) th.AssertEquals(t, newZone.Name, zoneName) - th.AssertEquals(t, newZone.TTL, 7200) + th.AssertEquals(t, 7200, newZone.TTL) return newZone, nil } @@ -115,7 +115,7 @@ func CreateSecondaryZone(t *testing.T, client *gophercloud.ServiceClient) (*zone t.Logf("Created Zone: %s", zoneName) th.AssertEquals(t, newZone.Name, zoneName) - th.AssertEquals(t, newZone.Masters[0], "10.0.0.1") + th.AssertEquals(t, "10.0.0.1", newZone.Masters[0]) return newZone, nil } @@ -338,7 +338,7 @@ func CreateTSIGKey(t *testing.T, client *gophercloud.ServiceClient) (*tsigkeys.T t.Logf("Created TSIG key: %s", keyName) th.AssertEquals(t, newTSIGKey.Name, keyName) - th.AssertEquals(t, newTSIGKey.Algorithm, "hmac-sha256") + th.AssertEquals(t, "hmac-sha256", newTSIGKey.Algorithm) return newTSIGKey, nil } diff --git a/internal/acceptance/openstack/dns/v2/recordsets_test.go b/internal/acceptance/openstack/dns/v2/recordsets_test.go index 7030791f6d..fcdb23210b 100644 --- a/internal/acceptance/openstack/dns/v2/recordsets_test.go +++ b/internal/acceptance/openstack/dns/v2/recordsets_test.go @@ -36,7 +36,7 @@ func TestRecordSetsListByZone(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) listOpts := recordsets.ListOpts{ Limit: 1, @@ -46,7 +46,7 @@ func TestRecordSetsListByZone(t *testing.T) { err = pager.EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) { rr, err := recordsets.ExtractRecordSets(page) th.AssertNoErr(t, err) - th.AssertEquals(t, len(rr), 1) + th.AssertEquals(t, 1, len(rr)) return true, nil }) th.AssertNoErr(t, err) @@ -79,7 +79,7 @@ func TestRecordSetsListAll(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) listOpts := recordsets.ListOpts{ Limit: 1, @@ -89,7 +89,7 @@ func TestRecordSetsListAll(t *testing.T) { err = pager.EachPage(context.TODO(), func(_ context.Context, page pagination.Page) (bool, error) { rr, err := recordsets.ExtractRecordSets(page) th.AssertNoErr(t, err) - th.AssertEquals(t, len(rr), 1) + th.AssertEquals(t, 1, len(rr)) return false, nil }) th.AssertNoErr(t, err) @@ -134,7 +134,7 @@ func TestRecordSetsCRUD(t *testing.T) { tools.PrintResource(t, &newRS) th.AssertDeepEquals(t, newRS.Records, records) - th.AssertEquals(t, newRS.TTL, 3600) + th.AssertEquals(t, 3600, newRS.TTL) ttl := 0 updateOpts = recordsets.UpdateOpts{ diff --git a/internal/acceptance/openstack/dns/v2/transfers_test.go b/internal/acceptance/openstack/dns/v2/transfers_test.go index 1149bfd0b3..87c78f773e 100644 --- a/internal/acceptance/openstack/dns/v2/transfers_test.go +++ b/internal/acceptance/openstack/dns/v2/transfers_test.go @@ -41,7 +41,7 @@ func TestTransferRequestCRUD(t *testing.T) { foundRequest = true } } - th.AssertEquals(t, foundRequest, true) + th.AssertEquals(t, true, foundRequest) description := "new description" updateOpts := transferRequests.UpdateOpts{ @@ -93,5 +93,5 @@ func TestTransferRequestAccept(t *testing.T) { foundAccept = true } } - th.AssertEquals(t, foundAccept, true) + th.AssertEquals(t, true, foundAccept) } diff --git a/internal/acceptance/openstack/dns/v2/tsigkeys_test.go b/internal/acceptance/openstack/dns/v2/tsigkeys_test.go index e07b695be2..33d695d487 100644 --- a/internal/acceptance/openstack/dns/v2/tsigkeys_test.go +++ b/internal/acceptance/openstack/dns/v2/tsigkeys_test.go @@ -39,7 +39,7 @@ func TestTSIGKeysCRUD(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) updateOpts := tsigkeys.UpdateOpts{ Name: tsigkey.Name + "-updated", @@ -52,5 +52,5 @@ func TestTSIGKeysCRUD(t *testing.T) { tools.PrintResource(t, &newTSIGKey) th.AssertEquals(t, newTSIGKey.Name, tsigkey.Name+"-updated") - th.AssertEquals(t, newTSIGKey.Secret, "updated-test-secret-key==") + th.AssertEquals(t, "updated-test-secret-key==", newTSIGKey.Secret) } diff --git a/internal/acceptance/openstack/dns/v2/zones_test.go b/internal/acceptance/openstack/dns/v2/zones_test.go index 2281094377..9becb6b024 100644 --- a/internal/acceptance/openstack/dns/v2/zones_test.go +++ b/internal/acceptance/openstack/dns/v2/zones_test.go @@ -37,7 +37,7 @@ func TestZonesCRUD(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) description := "" updateOpts := zones.UpdateOpts{ diff --git a/internal/acceptance/openstack/identity/v2/extension_test.go b/internal/acceptance/openstack/identity/v2/extension_test.go index f43523340a..e3ce3e8e58 100644 --- a/internal/acceptance/openstack/identity/v2/extension_test.go +++ b/internal/acceptance/openstack/identity/v2/extension_test.go @@ -33,7 +33,7 @@ func TestExtensionsList(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestExtensionsGet(t *testing.T) { diff --git a/internal/acceptance/openstack/identity/v2/role_test.go b/internal/acceptance/openstack/identity/v2/role_test.go index 49635f7f98..19e4478960 100644 --- a/internal/acceptance/openstack/identity/v2/role_test.go +++ b/internal/acceptance/openstack/identity/v2/role_test.go @@ -49,7 +49,7 @@ func TestRolesAddToUser(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestRolesList(t *testing.T) { @@ -73,5 +73,5 @@ func TestRolesList(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } diff --git a/internal/acceptance/openstack/identity/v2/tenant_test.go b/internal/acceptance/openstack/identity/v2/tenant_test.go index 2c7092e91d..b5d10eadee 100644 --- a/internal/acceptance/openstack/identity/v2/tenant_test.go +++ b/internal/acceptance/openstack/identity/v2/tenant_test.go @@ -34,7 +34,7 @@ func TestTenantsList(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestTenantsCRUD(t *testing.T) { diff --git a/internal/acceptance/openstack/identity/v2/user_test.go b/internal/acceptance/openstack/identity/v2/user_test.go index e0f614e511..466d053e90 100644 --- a/internal/acceptance/openstack/identity/v2/user_test.go +++ b/internal/acceptance/openstack/identity/v2/user_test.go @@ -34,7 +34,7 @@ func TestUsersList(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestUsersCreateUpdateDelete(t *testing.T) { diff --git a/internal/acceptance/openstack/identity/v3/applicationcredentials_test.go b/internal/acceptance/openstack/identity/v3/applicationcredentials_test.go index f8bb2ae129..a502c96a44 100644 --- a/internal/acceptance/openstack/identity/v3/applicationcredentials_test.go +++ b/internal/acceptance/openstack/identity/v3/applicationcredentials_test.go @@ -97,7 +97,7 @@ func TestApplicationCredentialsCRD(t *testing.T) { th.AssertEquals(t, applicationCredential.ExpiresAt, expiresAt) th.AssertEquals(t, applicationCredential.Name, createOpts.Name) th.AssertEquals(t, applicationCredential.Description, createOpts.Description) - th.AssertEquals(t, applicationCredential.Unrestricted, false) + th.AssertEquals(t, false, applicationCredential.Unrestricted) th.AssertEquals(t, applicationCredential.ProjectID, project.ID) checkACroles := rolesToMap(applicationCredential.Roles) @@ -124,7 +124,7 @@ func TestApplicationCredentialsCRD(t *testing.T) { th.AssertEquals(t, getApplicationCredential.ExpiresAt, expiresAt) th.AssertEquals(t, getApplicationCredential.Name, createOpts.Name) th.AssertEquals(t, getApplicationCredential.Description, createOpts.Description) - th.AssertEquals(t, getApplicationCredential.Unrestricted, false) + th.AssertEquals(t, false, getApplicationCredential.Unrestricted) th.AssertEquals(t, getApplicationCredential.ProjectID, project.ID) checkACroles = rolesToMap(getApplicationCredential.Roles) @@ -152,12 +152,12 @@ func TestApplicationCredentialsCRD(t *testing.T) { defer applicationcredentials.Delete(context.TODO(), client, user.ID, newApplicationCredential.ID) tools.PrintResource(t, newApplicationCredential) - th.AssertEquals(t, newApplicationCredential.ExpiresAt, time.Time{}) + th.AssertEquals(t, time.Time{}, newApplicationCredential.ExpiresAt) th.AssertEquals(t, newApplicationCredential.Name, createOpts.Name) th.AssertEquals(t, newApplicationCredential.Description, createOpts.Description) th.AssertEquals(t, newApplicationCredential.Secret, createOpts.Secret) - th.AssertEquals(t, newApplicationCredential.Unrestricted, true) - th.AssertEquals(t, newApplicationCredential.ExpiresAt, time.Time{}) + th.AssertEquals(t, true, newApplicationCredential.Unrestricted) + th.AssertEquals(t, time.Time{}, newApplicationCredential.ExpiresAt) th.AssertEquals(t, newApplicationCredential.ProjectID, project.ID) checkACroles = rolesToMap(newApplicationCredential.Roles) @@ -235,7 +235,7 @@ func TestApplicationCredentialsAccessRules(t *testing.T) { th.AssertEquals(t, applicationCredential.ExpiresAt, expiresAt) th.AssertEquals(t, applicationCredential.Name, createOpts.Name) th.AssertEquals(t, applicationCredential.Description, createOpts.Description) - th.AssertEquals(t, applicationCredential.Unrestricted, false) + th.AssertEquals(t, false, applicationCredential.Unrestricted) for i, rule := range applicationCredential.AccessRules { th.AssertEquals(t, rule.Path, apAccessRules[i].Path) @@ -255,7 +255,7 @@ func TestApplicationCredentialsAccessRules(t *testing.T) { th.AssertEquals(t, getApplicationCredential.ExpiresAt, expiresAt) th.AssertEquals(t, getApplicationCredential.Name, createOpts.Name) th.AssertEquals(t, getApplicationCredential.Description, createOpts.Description) - th.AssertEquals(t, getApplicationCredential.Unrestricted, false) + th.AssertEquals(t, false, getApplicationCredential.Unrestricted) for i, rule := range applicationCredential.AccessRules { th.AssertEquals(t, rule.Path, apAccessRules[i].Path) @@ -290,5 +290,5 @@ func TestApplicationCredentialsAccessRules(t *testing.T) { th.AssertNoErr(t, err) actual, err = applicationcredentials.ExtractAccessRules(allPages) th.AssertNoErr(t, err) - th.AssertEquals(t, len(actual), 0) + th.AssertEquals(t, 0, len(actual)) } diff --git a/internal/acceptance/openstack/identity/v3/domains_test.go b/internal/acceptance/openstack/identity/v3/domains_test.go index 28cbea7f70..6d32615bfd 100644 --- a/internal/acceptance/openstack/identity/v3/domains_test.go +++ b/internal/acceptance/openstack/identity/v3/domains_test.go @@ -55,7 +55,7 @@ func TestDomainsList(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestDomainsGet(t *testing.T) { @@ -69,7 +69,7 @@ func TestDomainsGet(t *testing.T) { tools.PrintResource(t, p) - th.AssertEquals(t, p.Name, "Default") + th.AssertEquals(t, "Default", p.Name) } func TestDomainsCRUD(t *testing.T) { diff --git a/internal/acceptance/openstack/identity/v3/endpoint_test.go b/internal/acceptance/openstack/identity/v3/endpoint_test.go index 8140a7d4f9..0ccbebc37b 100644 --- a/internal/acceptance/openstack/identity/v3/endpoint_test.go +++ b/internal/acceptance/openstack/identity/v3/endpoint_test.go @@ -36,7 +36,7 @@ func TestEndpointsList(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestEndpointsGet(t *testing.T) { @@ -79,7 +79,7 @@ func TestEndpointsNavigateCatalog(t *testing.T) { allServices, err := services.ExtractServices(allPages) th.AssertNoErr(t, err) - th.AssertEquals(t, len(allServices), 1) + th.AssertEquals(t, 1, len(allServices)) computeService := allServices[0] tools.PrintResource(t, computeService) @@ -96,7 +96,7 @@ func TestEndpointsNavigateCatalog(t *testing.T) { allEndpoints, err := endpoints.ExtractEndpoints(allPages) th.AssertNoErr(t, err) - th.AssertEquals(t, len(allServices), 1) + th.AssertEquals(t, 1, len(allServices)) tools.PrintResource(t, allEndpoints[0]) } @@ -138,6 +138,6 @@ func TestEndpointCRUD(t *testing.T) { }).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, newEndpoint.URL, "https://example-updated.com") + th.AssertEquals(t, "https://example-updated.com", newEndpoint.URL) th.AssertEquals(t, newEndpoint.Description, description) } diff --git a/internal/acceptance/openstack/identity/v3/groups_test.go b/internal/acceptance/openstack/identity/v3/groups_test.go index b60fbd5a71..bc353d5ca5 100644 --- a/internal/acceptance/openstack/identity/v3/groups_test.go +++ b/internal/acceptance/openstack/identity/v3/groups_test.go @@ -83,7 +83,7 @@ func TestGroupCRUD(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) listOpts.Filters = map[string]string{ "name__contains": "TEST", @@ -105,7 +105,7 @@ func TestGroupCRUD(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) listOpts.Filters = map[string]string{ "name__contains": "foo", @@ -127,7 +127,7 @@ func TestGroupCRUD(t *testing.T) { } } - th.AssertEquals(t, found, false) + th.AssertEquals(t, false, found) // Get the recently created group by ID p, err := groups.Get(context.TODO(), client, group.ID).Extract() diff --git a/internal/acceptance/openstack/identity/v3/oauth1_test.go b/internal/acceptance/openstack/identity/v3/oauth1_test.go index 7a2ef800ab..88307f4a77 100644 --- a/internal/acceptance/openstack/identity/v3/oauth1_test.go +++ b/internal/acceptance/openstack/identity/v3/oauth1_test.go @@ -179,7 +179,7 @@ func oauth1MethodTest(t *testing.T, client *gophercloud.ServiceClient, consumer found = true } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } // Get access token role @@ -193,7 +193,7 @@ func oauth1MethodTest(t *testing.T, client *gophercloud.ServiceClient, consumer found = true } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) // Test auth using OAuth1 newClient, err := clients.NewIdentityV3UnauthenticatedClient() diff --git a/internal/acceptance/openstack/identity/v3/projects_test.go b/internal/acceptance/openstack/identity/v3/projects_test.go index 12bac084fe..82d83bda16 100644 --- a/internal/acceptance/openstack/identity/v3/projects_test.go +++ b/internal/acceptance/openstack/identity/v3/projects_test.go @@ -55,7 +55,7 @@ func TestProjectsList(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) listOpts.Filters = map[string]string{ "name__contains": "dmi", @@ -76,7 +76,7 @@ func TestProjectsList(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) listOpts.Filters = map[string]string{ "name__contains": "foo", @@ -97,7 +97,7 @@ func TestProjectsList(t *testing.T) { } } - th.AssertEquals(t, found, false) + th.AssertEquals(t, false, found) } func TestProjectsGet(t *testing.T) { @@ -247,7 +247,7 @@ func TestProjectsTags(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) // Search using all tags, including a not existing one listOpts = projects.ListOpts{ @@ -260,7 +260,7 @@ func TestProjectsTags(t *testing.T) { allProjects, err = projects.ExtractProjects(allPages) th.AssertNoErr(t, err) - th.AssertEquals(t, len(allProjects), 0) + th.AssertEquals(t, 0, len(allProjects)) // Search matching at least one tag listOpts = projects.ListOpts{ @@ -282,7 +282,7 @@ func TestProjectsTags(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) // Search not matching any single tag listOpts = projects.ListOpts{ @@ -304,7 +304,7 @@ func TestProjectsTags(t *testing.T) { } } - th.AssertEquals(t, found, false) + th.AssertEquals(t, false, found) // Search matching not all tags listOpts = projects.ListOpts{ @@ -326,7 +326,7 @@ func TestProjectsTags(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) // Update the tags updateOpts := projects.UpdateOpts{ @@ -337,8 +337,8 @@ func TestProjectsTags(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, updatedProject) - th.AssertEquals(t, len(updatedProject.Tags), 1) - th.AssertEquals(t, updatedProject.Tags[0], "Tag1") + th.AssertEquals(t, 1, len(updatedProject.Tags)) + th.AssertEquals(t, "Tag1", updatedProject.Tags[0]) // Update the project, but not its tags description := "Test description" @@ -350,8 +350,8 @@ func TestProjectsTags(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, updatedProject) - th.AssertEquals(t, len(updatedProject.Tags), 1) - th.AssertEquals(t, updatedProject.Tags[0], "Tag1") + th.AssertEquals(t, 1, len(updatedProject.Tags)) + th.AssertEquals(t, "Tag1", updatedProject.Tags[0]) // Remove all Tags updateOpts = projects.UpdateOpts{ @@ -362,7 +362,7 @@ func TestProjectsTags(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, updatedProject) - th.AssertEquals(t, len(updatedProject.Tags), 0) + th.AssertEquals(t, 0, len(updatedProject.Tags)) } func TestProjectsTagsCRUD(t *testing.T) { diff --git a/internal/acceptance/openstack/identity/v3/roles_test.go b/internal/acceptance/openstack/identity/v3/roles_test.go index 753736843a..499888a7e7 100644 --- a/internal/acceptance/openstack/identity/v3/roles_test.go +++ b/internal/acceptance/openstack/identity/v3/roles_test.go @@ -96,7 +96,7 @@ func TestRolesCRUD(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) description := "updated role test" updateOpts := roles.UpdateOpts{ Description: &description, @@ -115,7 +115,7 @@ func TestRolesCRUD(t *testing.T) { tools.PrintResource(t, newRole.Extra) th.AssertEquals(t, newRole.Description, description) - th.AssertEquals(t, newRole.Extra["email"], "updatedtestrole@example.com") + th.AssertEquals(t, "updatedtestrole@example.com", newRole.Extra["email"]) } @@ -158,7 +158,7 @@ func TestRolesFilterList(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) listOpts.Filters = map[string]string{ "name__contains": "reader", @@ -180,7 +180,7 @@ func TestRolesFilterList(t *testing.T) { } } - th.AssertEquals(t, found, false) + th.AssertEquals(t, false, found) } func TestRoleListAssignmentIncludeNamesAndSubtree(t *testing.T) { @@ -248,7 +248,7 @@ func TestRoleListAssignmentIncludeNamesAndSubtree(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestRoleListAssignmentForUserOnProject(t *testing.T) { @@ -310,7 +310,7 @@ func TestRoleListAssignmentForUserOnProject(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestRoleListAssignmentForUserOnDomain(t *testing.T) { @@ -375,7 +375,7 @@ func TestRoleListAssignmentForUserOnDomain(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestRoleListAssignmentForGroupOnProject(t *testing.T) { @@ -440,7 +440,7 @@ func TestRoleListAssignmentForGroupOnProject(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestRoleListAssignmentForGroupOnDomain(t *testing.T) { @@ -508,7 +508,7 @@ func TestRoleListAssignmentForGroupOnDomain(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestRolesAssignToUserOnProject(t *testing.T) { @@ -578,7 +578,7 @@ func TestRolesAssignToUserOnProject(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestRolesAssignToUserOnDomain(t *testing.T) { @@ -651,7 +651,7 @@ func TestRolesAssignToUserOnDomain(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestRolesAssignToGroupOnDomain(t *testing.T) { @@ -727,7 +727,7 @@ func TestRolesAssignToGroupOnDomain(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestRolesAssignToGroupOnProject(t *testing.T) { @@ -800,7 +800,7 @@ func TestRolesAssignToGroupOnProject(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestCRUDRoleInferenceRule(t *testing.T) { diff --git a/internal/acceptance/openstack/identity/v3/service_test.go b/internal/acceptance/openstack/identity/v3/service_test.go index 8686f2c890..a850952a71 100644 --- a/internal/acceptance/openstack/identity/v3/service_test.go +++ b/internal/acceptance/openstack/identity/v3/service_test.go @@ -37,7 +37,7 @@ func TestServicesList(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestServicesCRUD(t *testing.T) { @@ -75,5 +75,5 @@ func TestServicesCRUD(t *testing.T) { tools.PrintResource(t, newService) tools.PrintResource(t, newService.Extra) - th.AssertEquals(t, newService.Extra["description"], "Test Users") + th.AssertEquals(t, "Test Users", newService.Extra["description"]) } diff --git a/internal/acceptance/openstack/identity/v3/trusts_test.go b/internal/acceptance/openstack/identity/v3/trusts_test.go index 225e09d4b0..db20d24883 100644 --- a/internal/acceptance/openstack/identity/v3/trusts_test.go +++ b/internal/acceptance/openstack/identity/v3/trusts_test.go @@ -112,7 +112,7 @@ func TestTrustCRUD(t *testing.T) { p, err := trusts.Get(context.TODO(), client, trust.ID).Extract() th.AssertNoErr(t, err) th.AssertEquals(t, p.ExpiresAt, expiresAt) - th.AssertEquals(t, p.DeletedAt.IsZero(), true) + th.AssertEquals(t, true, p.DeletedAt.IsZero()) tools.PrintResource(t, p) @@ -121,7 +121,7 @@ func TestTrustCRUD(t *testing.T) { th.AssertNoErr(t, err) allTrustRoles, err := trusts.ExtractRoles(rolesPages) th.AssertNoErr(t, err) - th.AssertEquals(t, len(allTrustRoles), 1) + th.AssertEquals(t, 1, len(allTrustRoles)) th.AssertEquals(t, allTrustRoles[0].ID, memberRoleID) // Get trust role diff --git a/internal/acceptance/openstack/identity/v3/users_test.go b/internal/acceptance/openstack/identity/v3/users_test.go index 31b04b7512..a1b310a6a2 100644 --- a/internal/acceptance/openstack/identity/v3/users_test.go +++ b/internal/acceptance/openstack/identity/v3/users_test.go @@ -41,7 +41,7 @@ func TestUsersList(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) listOpts.Filters = map[string]string{ "name__contains": "dmi", @@ -63,7 +63,7 @@ func TestUsersList(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) listOpts.Filters = map[string]string{ "name__contains": "foo", @@ -85,7 +85,7 @@ func TestUsersList(t *testing.T) { } } - th.AssertEquals(t, found, false) + th.AssertEquals(t, false, found) } func TestUsersGet(t *testing.T) { @@ -172,7 +172,7 @@ func TestUserCRUD(t *testing.T) { th.AssertEquals(t, newUser.Name, name) th.AssertEquals(t, newUser.Description, description) th.AssertEquals(t, newUser.Enabled, iFalse) - th.AssertEquals(t, newUser.Extra["disabled_reason"], "DDOS") + th.AssertEquals(t, "DDOS", newUser.Extra["disabled_reason"]) } func TestUserChangePassword(t *testing.T) { @@ -251,7 +251,7 @@ func TestUsersGroups(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) found = false allUserPages, err := users.ListInGroup(client, group.ID, nil).AllPages(context.TODO()) @@ -269,7 +269,7 @@ func TestUsersGroups(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) ok, err := users.IsMemberOfGroup(context.TODO(), client, group.ID, user.ID).Extract() if err != nil { @@ -298,7 +298,7 @@ func TestUsersGroups(t *testing.T) { } } - th.AssertEquals(t, found, false) + th.AssertEquals(t, false, found) found = false allUserPages, err = users.ListInGroup(client, group.ID, nil).AllPages(context.TODO()) @@ -316,7 +316,7 @@ func TestUsersGroups(t *testing.T) { } } - th.AssertEquals(t, found, false) + th.AssertEquals(t, false, found) } diff --git a/internal/acceptance/openstack/image/v2/images_test.go b/internal/acceptance/openstack/image/v2/images_test.go index 2053a2047b..0b560c1ee8 100644 --- a/internal/acceptance/openstack/image/v2/images_test.go +++ b/internal/acceptance/openstack/image/v2/images_test.go @@ -66,7 +66,7 @@ func TestImagesListAllPages(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestImagesListByDate(t *testing.T) { @@ -175,7 +175,7 @@ func TestImagesUpdate(t *testing.T) { tools.PrintResource(t, newImage.Properties) th.AssertEquals(t, newImage.Name, image.Name+"foo") - th.AssertEquals(t, newImage.Protected, true) + th.AssertEquals(t, true, newImage.Protected) sort.Strings(newTags) sort.Strings(newImage.Tags) @@ -183,7 +183,7 @@ func TestImagesUpdate(t *testing.T) { // Because OpenStack is now adding additional properties automatically, // it's not possible to do an easy AssertDeepEquals. - th.AssertEquals(t, newImage.Properties["hw_disk_bus"], "scsi") + th.AssertEquals(t, "scsi", newImage.Properties["hw_disk_bus"]) if _, ok := newImage.Properties["architecture"]; ok { t.Fatal("architecture property still exists") diff --git a/internal/acceptance/openstack/image/v2/imageservice.go b/internal/acceptance/openstack/image/v2/imageservice.go index 0454a74b88..8af457fc22 100644 --- a/internal/acceptance/openstack/image/v2/imageservice.go +++ b/internal/acceptance/openstack/image/v2/imageservice.go @@ -56,8 +56,8 @@ func CreateEmptyImage(t *testing.T, client *gophercloud.ServiceClient) (*images. t.Logf("Created image %s: %#v", name, newImage) th.CheckEquals(t, newImage.Name, name) - th.CheckEquals(t, newImage.Properties["architecture"], "x86_64") - th.CheckEquals(t, newImage.Properties["properties"], "{'hypervisor_type': 'qemu', 'architecture': 'x86_64'}") + th.CheckEquals(t, "x86_64", newImage.Properties["architecture"]) + th.CheckEquals(t, "{'hypervisor_type': 'qemu', 'architecture': 'x86_64'}", newImage.Properties["properties"]) return newImage, nil } diff --git a/internal/acceptance/openstack/keymanager/v1/acls_test.go b/internal/acceptance/openstack/keymanager/v1/acls_test.go index ab9cd61716..2045c51e49 100644 --- a/internal/acceptance/openstack/keymanager/v1/acls_test.go +++ b/internal/acceptance/openstack/keymanager/v1/acls_test.go @@ -49,8 +49,8 @@ func TestACLCRUD(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, acl) tools.PrintResource(t, (*acl)["read"].Created) - th.AssertEquals(t, len((*acl)["read"].Users), 1) - th.AssertEquals(t, (*acl)["read"].ProjectAccess, false) + th.AssertEquals(t, 1, len((*acl)["read"].Users)) + th.AssertEquals(t, false, (*acl)["read"].ProjectAccess) newUsers := []string{} updateOpts := acls.SetOpts{ @@ -68,8 +68,8 @@ func TestACLCRUD(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, acl) tools.PrintResource(t, (*acl)["read"].Created) - th.AssertEquals(t, len((*acl)["read"].Users), 0) - th.AssertEquals(t, (*acl)["read"].ProjectAccess, false) + th.AssertEquals(t, 0, len((*acl)["read"].Users)) + th.AssertEquals(t, false, (*acl)["read"].ProjectAccess) container, err := CreateGenericContainer(t, client, secret) th.AssertNoErr(t, err) @@ -92,8 +92,8 @@ func TestACLCRUD(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, acl) tools.PrintResource(t, (*acl)["read"].Created) - th.AssertEquals(t, len((*acl)["read"].Users), 1) - th.AssertEquals(t, (*acl)["read"].ProjectAccess, false) + th.AssertEquals(t, 1, len((*acl)["read"].Users)) + th.AssertEquals(t, false, (*acl)["read"].ProjectAccess) aclRef, err = acls.UpdateContainerACL(context.TODO(), client, containerID, updateOpts).Extract() th.AssertNoErr(t, err) @@ -103,6 +103,6 @@ func TestACLCRUD(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, acl) tools.PrintResource(t, (*acl)["read"].Created) - th.AssertEquals(t, len((*acl)["read"].Users), 0) - th.AssertEquals(t, (*acl)["read"].ProjectAccess, false) + th.AssertEquals(t, 0, len((*acl)["read"].Users)) + th.AssertEquals(t, false, (*acl)["read"].ProjectAccess) } diff --git a/internal/acceptance/openstack/keymanager/v1/containers_test.go b/internal/acceptance/openstack/keymanager/v1/containers_test.go index 9ebb5b3058..d16e385d9e 100644 --- a/internal/acceptance/openstack/keymanager/v1/containers_test.go +++ b/internal/acceptance/openstack/keymanager/v1/containers_test.go @@ -53,7 +53,7 @@ func TestGenericContainersCRUD(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestCertificateContainer(t *testing.T) { @@ -172,7 +172,7 @@ func TestContainerConsumersCRUD(t *testing.T) { container, err = containers.CreateConsumer(context.TODO(), client, containerID, consumerCreateOpts).Extract() th.AssertNoErr(t, err) tools.PrintResource(t, container.Consumers) - th.AssertEquals(t, len(container.Consumers), 1) + th.AssertEquals(t, 1, len(container.Consumers)) defer func() { deleteOpts := containers.DeleteConsumerOpts{ Name: consumerName, @@ -181,7 +181,7 @@ func TestContainerConsumersCRUD(t *testing.T) { container, err := containers.DeleteConsumer(context.TODO(), client, containerID, deleteOpts).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, len(container.Consumers), 0) + th.AssertEquals(t, 0, len(container.Consumers)) }() allPages, err := containers.ListConsumers(client, containerID, nil).AllPages(context.TODO()) @@ -197,5 +197,5 @@ func TestContainerConsumersCRUD(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } diff --git a/internal/acceptance/openstack/keymanager/v1/keymanager.go b/internal/acceptance/openstack/keymanager/v1/keymanager.go index 87a965eb5c..1827797b21 100644 --- a/internal/acceptance/openstack/keymanager/v1/keymanager.go +++ b/internal/acceptance/openstack/keymanager/v1/keymanager.go @@ -63,7 +63,7 @@ func CreateAsymmetricOrder(t *testing.T, client *gophercloud.ServiceClient) (*or tools.PrintResource(t, order.Meta.Expiration) th.AssertEquals(t, order.Meta.Name, name) - th.AssertEquals(t, order.Type, "asymmetric") + th.AssertEquals(t, "asymmetric", order.Type) return order, nil } @@ -114,7 +114,7 @@ func CreateCertificateContainer(t *testing.T, client *gophercloud.ServiceClient, tools.PrintResource(t, container) th.AssertEquals(t, container.Name, containerName) - th.AssertEquals(t, container.Type, "certificate") + th.AssertEquals(t, "certificate", container.Type) return container, nil } @@ -156,7 +156,7 @@ func CreateKeyOrder(t *testing.T, client *gophercloud.ServiceClient) (*orders.Or tools.PrintResource(t, order.Meta.Expiration) th.AssertEquals(t, order.Meta.Name, name) - th.AssertEquals(t, order.Type, "key") + th.AssertEquals(t, "key", order.Type) return order, nil } @@ -207,7 +207,7 @@ func CreateRSAContainer(t *testing.T, client *gophercloud.ServiceClient, passphr tools.PrintResource(t, container) th.AssertEquals(t, container.Name, containerName) - th.AssertEquals(t, container.Type, "rsa") + th.AssertEquals(t, "rsa", container.Type) return container, nil } @@ -249,7 +249,7 @@ func CreateCertificateSecret(t *testing.T, client *gophercloud.ServiceClient, ce tools.PrintResource(t, secret) th.AssertEquals(t, secret.Name, name) - th.AssertEquals(t, secret.Algorithm, "rsa") + th.AssertEquals(t, "rsa", secret.Algorithm) return secret, nil } @@ -289,7 +289,7 @@ func CreateEmptySecret(t *testing.T, client *gophercloud.ServiceClient) (*secret tools.PrintResource(t, secret) th.AssertEquals(t, secret.Name, secretName) - th.AssertEquals(t, secret.Algorithm, "aes") + th.AssertEquals(t, "aes", secret.Algorithm) return secret, nil } @@ -333,7 +333,7 @@ func CreateGenericContainer(t *testing.T, client *gophercloud.ServiceClient, sec tools.PrintResource(t, container) th.AssertEquals(t, container.Name, containerName) - th.AssertEquals(t, container.Type, "generic") + th.AssertEquals(t, "generic", container.Type) return container, nil } @@ -423,7 +423,7 @@ func CreatePassphraseSecret(t *testing.T, client *gophercloud.ServiceClient, pas tools.PrintResource(t, secret) th.AssertEquals(t, secret.Name, secretName) - th.AssertEquals(t, secret.Algorithm, "aes") + th.AssertEquals(t, "aes", secret.Algorithm) return secret, nil } @@ -465,7 +465,7 @@ func CreatePublicSecret(t *testing.T, client *gophercloud.ServiceClient, pub []b tools.PrintResource(t, secret) th.AssertEquals(t, secret.Name, name) - th.AssertEquals(t, secret.Algorithm, "rsa") + th.AssertEquals(t, "rsa", secret.Algorithm) return secret, nil } @@ -507,7 +507,7 @@ func CreatePrivateSecret(t *testing.T, client *gophercloud.ServiceClient, priv [ tools.PrintResource(t, secret) th.AssertEquals(t, secret.Name, name) - th.AssertEquals(t, secret.Algorithm, "rsa") + th.AssertEquals(t, "rsa", secret.Algorithm) return secret, nil } @@ -551,7 +551,7 @@ func CreateSecretWithPayload(t *testing.T, client *gophercloud.ServiceClient, pa tools.PrintResource(t, secret) th.AssertEquals(t, secret.Name, secretName) - th.AssertEquals(t, secret.Algorithm, "aes") + th.AssertEquals(t, "aes", secret.Algorithm) th.AssertEquals(t, secret.Expiration, expiration) return secret, nil @@ -597,7 +597,7 @@ func CreateSymmetricSecret(t *testing.T, client *gophercloud.ServiceClient) (*se tools.PrintResource(t, secret) th.AssertEquals(t, secret.Name, name) - th.AssertEquals(t, secret.Algorithm, "aes") + th.AssertEquals(t, "aes", secret.Algorithm) return secret, nil } diff --git a/internal/acceptance/openstack/keymanager/v1/orders_test.go b/internal/acceptance/openstack/keymanager/v1/orders_test.go index b5235ff88f..75b098c3fe 100644 --- a/internal/acceptance/openstack/keymanager/v1/orders_test.go +++ b/internal/acceptance/openstack/keymanager/v1/orders_test.go @@ -49,7 +49,7 @@ func TestOrdersCRUD(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestOrdersAsymmetric(t *testing.T) { diff --git a/internal/acceptance/openstack/keymanager/v1/secrets_test.go b/internal/acceptance/openstack/keymanager/v1/secrets_test.go index 078d190587..ec81b3e433 100644 --- a/internal/acceptance/openstack/keymanager/v1/secrets_test.go +++ b/internal/acceptance/openstack/keymanager/v1/secrets_test.go @@ -52,7 +52,7 @@ func TestSecretsCRUD(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestSecretsDelayedPayload(t *testing.T) { @@ -105,8 +105,8 @@ func TestSecretsMetadataCRUD(t *testing.T) { metadata, err := secrets.GetMetadata(context.TODO(), client, secretID).Extract() th.AssertNoErr(t, err) tools.PrintResource(t, metadata) - th.AssertEquals(t, metadata["foo"], "bar") - th.AssertEquals(t, metadata["something"], "something else") + th.AssertEquals(t, "bar", metadata["foo"]) + th.AssertEquals(t, "something else", metadata["something"]) // Add a single metadatum metadatumOpts := secrets.MetadatumOpts{ @@ -120,10 +120,10 @@ func TestSecretsMetadataCRUD(t *testing.T) { metadata, err = secrets.GetMetadata(context.TODO(), client, secretID).Extract() th.AssertNoErr(t, err) tools.PrintResource(t, metadata) - th.AssertEquals(t, len(metadata), 3) - th.AssertEquals(t, metadata["foo"], "bar") - th.AssertEquals(t, metadata["something"], "something else") - th.AssertEquals(t, metadata["bar"], "baz") + th.AssertEquals(t, 3, len(metadata)) + th.AssertEquals(t, "bar", metadata["foo"]) + th.AssertEquals(t, "something else", metadata["something"]) + th.AssertEquals(t, "baz", metadata["bar"]) // Update a metadatum metadatumOpts.Key = "foo" @@ -132,16 +132,16 @@ func TestSecretsMetadataCRUD(t *testing.T) { metadatum, err := secrets.UpdateMetadatum(context.TODO(), client, secretID, metadatumOpts).Extract() th.AssertNoErr(t, err) tools.PrintResource(t, metadatum) - th.AssertDeepEquals(t, metadatum.Key, "foo") - th.AssertDeepEquals(t, metadatum.Value, "foo") + th.AssertDeepEquals(t, "foo", metadatum.Key) + th.AssertDeepEquals(t, "foo", metadatum.Value) metadata, err = secrets.GetMetadata(context.TODO(), client, secretID).Extract() th.AssertNoErr(t, err) tools.PrintResource(t, metadata) - th.AssertEquals(t, len(metadata), 3) - th.AssertEquals(t, metadata["foo"], "foo") - th.AssertEquals(t, metadata["something"], "something else") - th.AssertEquals(t, metadata["bar"], "baz") + th.AssertEquals(t, 3, len(metadata)) + th.AssertEquals(t, "foo", metadata["foo"]) + th.AssertEquals(t, "something else", metadata["something"]) + th.AssertEquals(t, "baz", metadata["bar"]) // Delete a metadatum err = secrets.DeleteMetadatum(context.TODO(), client, secretID, "foo").ExtractErr() @@ -150,9 +150,9 @@ func TestSecretsMetadataCRUD(t *testing.T) { metadata, err = secrets.GetMetadata(context.TODO(), client, secretID).Extract() th.AssertNoErr(t, err) tools.PrintResource(t, metadata) - th.AssertEquals(t, len(metadata), 2) - th.AssertEquals(t, metadata["something"], "something else") - th.AssertEquals(t, metadata["bar"], "baz") + th.AssertEquals(t, 2, len(metadata)) + th.AssertEquals(t, "something else", metadata["something"]) + th.AssertEquals(t, "baz", metadata["bar"]) } func TestSymmetricSecret(t *testing.T) { diff --git a/internal/acceptance/openstack/loadbalancer/v2/loadbalancer.go b/internal/acceptance/openstack/loadbalancer/v2/loadbalancer.go index 8490d27f36..0b707dac71 100644 --- a/internal/acceptance/openstack/loadbalancer/v2/loadbalancer.go +++ b/internal/acceptance/openstack/loadbalancer/v2/loadbalancer.go @@ -154,7 +154,7 @@ func CreateLoadBalancer(t *testing.T, client *gophercloud.ServiceClient, subnetI th.AssertEquals(t, lb.Name, lbName) th.AssertEquals(t, lb.Description, lbDescription) th.AssertEquals(t, lb.VipSubnetID, subnetID) - th.AssertEquals(t, lb.AdminStateUp, true) + th.AssertEquals(t, true, lb.AdminStateUp) if len(tags) > 0 { th.AssertDeepEquals(t, lb.Tags, tags) @@ -252,34 +252,34 @@ func CreateLoadBalancerFullyPopulated(t *testing.T, client *gophercloud.ServiceC th.AssertEquals(t, lb.Name, lbName) th.AssertEquals(t, lb.Description, lbDescription) th.AssertEquals(t, lb.VipSubnetID, subnetID) - th.AssertEquals(t, lb.AdminStateUp, true) + th.AssertEquals(t, true, lb.AdminStateUp) - th.AssertEquals(t, len(lb.Listeners), 1) + th.AssertEquals(t, 1, len(lb.Listeners)) th.AssertEquals(t, lb.Listeners[0].Name, listenerName) th.AssertEquals(t, lb.Listeners[0].Description, listenerDescription) th.AssertEquals(t, lb.Listeners[0].ProtocolPort, listenerPort) - th.AssertEquals(t, len(lb.Listeners[0].L7Policies), 1) + th.AssertEquals(t, 1, len(lb.Listeners[0].L7Policies)) th.AssertEquals(t, lb.Listeners[0].L7Policies[0].Name, policyName) th.AssertEquals(t, lb.Listeners[0].L7Policies[0].Description, policyDescription) th.AssertEquals(t, lb.Listeners[0].L7Policies[0].Description, policyDescription) - th.AssertEquals(t, len(lb.Listeners[0].L7Policies[0].Rules), 1) + th.AssertEquals(t, 1, len(lb.Listeners[0].L7Policies[0].Rules)) - th.AssertEquals(t, len(lb.Pools), 1) + th.AssertEquals(t, 1, len(lb.Pools)) th.AssertEquals(t, lb.Pools[0].Name, poolName) th.AssertEquals(t, lb.Pools[0].Description, poolDescription) - th.AssertEquals(t, len(lb.Pools[0].Members), 1) + th.AssertEquals(t, 1, len(lb.Pools[0].Members)) th.AssertEquals(t, lb.Pools[0].Members[0].Name, memberName) th.AssertEquals(t, lb.Pools[0].Members[0].ProtocolPort, memberPort) th.AssertEquals(t, lb.Pools[0].Members[0].Weight, memberWeight) - th.AssertEquals(t, lb.Pools[0].Monitor.Delay, 10) - th.AssertEquals(t, lb.Pools[0].Monitor.Timeout, 5) - th.AssertEquals(t, lb.Pools[0].Monitor.MaxRetries, 5) - th.AssertEquals(t, lb.Pools[0].Monitor.MaxRetriesDown, 4) + th.AssertEquals(t, 10, lb.Pools[0].Monitor.Delay) + th.AssertEquals(t, 5, lb.Pools[0].Monitor.Timeout) + th.AssertEquals(t, 5, lb.Pools[0].Monitor.MaxRetries) + th.AssertEquals(t, 4, lb.Pools[0].Monitor.MaxRetriesDown) th.AssertEquals(t, lb.Pools[0].Monitor.Type, string(monitors.TypeHTTP)) - th.AssertEquals(t, lb.Pools[0].Monitor.HTTPVersion, "1.0") + th.AssertEquals(t, "1.0", lb.Pools[0].Monitor.HTTPVersion) if len(tags) > 0 { th.AssertDeepEquals(t, lb.Tags, tags) @@ -358,11 +358,11 @@ func CreateMonitor(t *testing.T, client *gophercloud.ServiceClient, lb *loadbala th.AssertEquals(t, monitor.Name, monitorName) th.AssertEquals(t, monitor.Type, monitors.TypePING) - th.AssertEquals(t, monitor.Delay, 10) - th.AssertEquals(t, monitor.Timeout, 5) - th.AssertEquals(t, monitor.MaxRetries, 5) - th.AssertEquals(t, monitor.MaxRetriesDown, 4) - th.AssertEquals(t, monitor.HTTPVersion, "1.1") + th.AssertEquals(t, 10, monitor.Delay) + th.AssertEquals(t, 5, monitor.Timeout) + th.AssertEquals(t, 5, monitor.MaxRetries) + th.AssertEquals(t, 4, monitor.MaxRetriesDown) + th.AssertEquals(t, "1.1", monitor.HTTPVersion) return monitor, nil } @@ -474,7 +474,7 @@ func CreateL7Policy(t *testing.T, client *gophercloud.ServiceClient, listener *l th.AssertEquals(t, policy.Description, policyDescription) th.AssertEquals(t, policy.ListenerID, listener.ID) th.AssertEquals(t, policy.Action, string(l7policies.ActionRedirectToURL)) - th.AssertEquals(t, policy.RedirectURL, "http://www.example.com") + th.AssertEquals(t, "http://www.example.com", policy.RedirectURL) th.AssertDeepEquals(t, policy.Tags, tags) return policy, nil @@ -504,7 +504,7 @@ func CreateL7Rule(t *testing.T, client *gophercloud.ServiceClient, policyID stri th.AssertEquals(t, rule.RuleType, string(l7policies.TypePath)) th.AssertEquals(t, rule.CompareType, string(l7policies.CompareTypeStartWith)) - th.AssertEquals(t, rule.Value, "/api") + th.AssertEquals(t, "/api", rule.Value) th.AssertDeepEquals(t, rule.Tags, tags) return rule, nil diff --git a/internal/acceptance/openstack/loadbalancer/v2/loadbalancers_test.go b/internal/acceptance/openstack/loadbalancer/v2/loadbalancers_test.go index 98556fbc25..8724cbabdd 100644 --- a/internal/acceptance/openstack/loadbalancer/v2/loadbalancers_test.go +++ b/internal/acceptance/openstack/loadbalancer/v2/loadbalancers_test.go @@ -406,7 +406,7 @@ func TestLoadbalancersCRUD(t *testing.T) { tools.PrintResource(t, newListener) - th.AssertEquals(t, newListener.DefaultPoolID, "") + th.AssertEquals(t, "", newListener.DefaultPoolID) // Member member, err := CreateMember(t, lbClient, lb, pool, subnet.ID, subnet.CIDR) diff --git a/internal/acceptance/openstack/metric/v1/metrics_test.go b/internal/acceptance/openstack/metric/v1/metrics_test.go index 6fee465d62..9aa021457e 100644 --- a/internal/acceptance/openstack/metric/v1/metrics_test.go +++ b/internal/acceptance/openstack/metric/v1/metrics_test.go @@ -22,7 +22,7 @@ func TestMetricQuery(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, result) - th.AssertEquals(t, result.ResultType, "vector") + th.AssertEquals(t, "vector", result.ResultType) } func TestMetricLabels(t *testing.T) { diff --git a/internal/acceptance/openstack/networking/v2/extensions/bgp/speakers/bgpspeakers_test.go b/internal/acceptance/openstack/networking/v2/extensions/bgp/speakers/bgpspeakers_test.go index 9f6eb59c95..1917f5f2f1 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/bgp/speakers/bgpspeakers_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/bgp/speakers/bgpspeakers_test.go @@ -81,7 +81,7 @@ func TestBGPSpeakerCRUD(t *testing.T) { th.AssertNoErr(t, err) speakerGot, err = speakers.Get(context.TODO(), client, bgpSpeaker.ID).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, len(speakerGot.Networks), 0) + th.AssertEquals(t, 0, len(speakerGot.Networks)) t.Logf("Successfully removed BGP Peer %s to BGP Speaker %s", bgpPeer.Name, speakerUpdated.Name) // GetAdvertisedRoutes diff --git a/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/fwaas_v2.go b/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/fwaas_v2.go index 805b2265be..74dda5a8e5 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/fwaas_v2.go +++ b/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/fwaas_v2.go @@ -64,7 +64,7 @@ func CreatePolicy(t *testing.T, client *gophercloud.ServiceClient, ruleID string th.AssertEquals(t, policy.Name, policyName) th.AssertEquals(t, policy.Description, policyDescription) - th.AssertEquals(t, len(policy.Rules), 1) + th.AssertEquals(t, 1, len(policy.Rules)) return policy, nil } diff --git a/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/groups_test.go b/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/groups_test.go index b8ee611c95..3b8b4b5913 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/groups_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/groups_test.go @@ -73,7 +73,7 @@ func TestGroupCRUD(t *testing.T) { t.Fatalf("Unable to remove ingress firewall policy from firewall group %s: %v", removeIngressPolicy.ID, err) } - th.AssertEquals(t, removeIngressPolicy.IngressFirewallPolicyID, "") + th.AssertEquals(t, "", removeIngressPolicy.IngressFirewallPolicyID) th.AssertEquals(t, removeIngressPolicy.EgressFirewallPolicyID, firewall_policy_id) t.Logf("Ingress policy removed from firewall group %s", updatedGroup.ID) @@ -83,7 +83,7 @@ func TestGroupCRUD(t *testing.T) { t.Fatalf("Unable to remove egress firewall policy from firewall group %s: %v", removeEgressPolicy.ID, err) } - th.AssertEquals(t, removeEgressPolicy.EgressFirewallPolicyID, "") + th.AssertEquals(t, "", removeEgressPolicy.EgressFirewallPolicyID) t.Logf("Egress policy removed from firewall group %s", updatedGroup.ID) @@ -102,5 +102,5 @@ func TestGroupCRUD(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } diff --git a/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/policy_test.go b/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/policy_test.go index 881e9a87aa..5467db42d0 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/policy_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/policy_test.go @@ -68,7 +68,7 @@ func TestPolicyCRUD(t *testing.T) { tools.PrintResource(t, newPolicy) th.AssertEquals(t, newPolicy.Name, name) th.AssertEquals(t, newPolicy.Description, description) - th.AssertEquals(t, len(newPolicy.Rules), 0) + th.AssertEquals(t, 0, len(newPolicy.Rules)) allPages, err := policies.List(client, nil).AllPages(context.TODO()) th.AssertNoErr(t, err) @@ -83,5 +83,5 @@ func TestPolicyCRUD(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } diff --git a/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/rule_test.go b/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/rule_test.go index 53de93fa84..54b18384d4 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/rule_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/rule_test.go @@ -68,5 +68,5 @@ func TestRuleCRUD(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } diff --git a/internal/acceptance/openstack/networking/v2/extensions/layer3/addressscopes_test.go b/internal/acceptance/openstack/networking/v2/extensions/layer3/addressscopes_test.go index bb4c8ce2d4..9daad75037 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/layer3/addressscopes_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/layer3/addressscopes_test.go @@ -50,5 +50,5 @@ func TestAddressScopesCRUD(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } diff --git a/internal/acceptance/openstack/networking/v2/extensions/layer3/floatingips_test.go b/internal/acceptance/openstack/networking/v2/extensions/layer3/floatingips_test.go index 5f4d771614..aaecb86999 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/layer3/floatingips_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/layer3/floatingips_test.go @@ -44,7 +44,7 @@ func TestLayer3FloatingIPsCreateDelete(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestLayer3FloatingIPsExternalCreateDelete(t *testing.T) { @@ -100,7 +100,7 @@ func TestLayer3FloatingIPsExternalCreateDelete(t *testing.T) { tools.PrintResource(t, newFip) - th.AssertEquals(t, newFip.PortID, "") + th.AssertEquals(t, "", newFip.PortID) } func TestLayer3FloatingIPsWithFixedIPsExternalCreateDelete(t *testing.T) { diff --git a/internal/acceptance/openstack/networking/v2/extensions/layer3/l3_scheduling_test.go b/internal/acceptance/openstack/networking/v2/extensions/layer3/l3_scheduling_test.go index f186118d44..3efd72a7c5 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/layer3/l3_scheduling_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/layer3/l3_scheduling_test.go @@ -64,7 +64,7 @@ func TestLayer3RouterScheduling(t *testing.T) { // List routers on hosting agent routersOnHostingAgent, err := agents.ListL3Routers(context.TODO(), client, hostingAgent.ID).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, containsRouterFunc(routersOnHostingAgent, router.ID), false) + th.AssertEquals(t, false, containsRouterFunc(routersOnHostingAgent, router.ID)) t.Logf("Router %s is not scheduled on %s", router.ID, hostingAgent.ID) // schedule back @@ -74,6 +74,6 @@ func TestLayer3RouterScheduling(t *testing.T) { // List hosting agent after readding routersOnHostingAgent, err = agents.ListL3Routers(context.TODO(), client, hostingAgent.ID).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, containsRouterFunc(routersOnHostingAgent, router.ID), true) + th.AssertEquals(t, true, containsRouterFunc(routersOnHostingAgent, router.ID)) t.Logf("Router %s is scheduled on %s", router.ID, hostingAgent.ID) } diff --git a/internal/acceptance/openstack/networking/v2/extensions/layer3/layer3.go b/internal/acceptance/openstack/networking/v2/extensions/layer3/layer3.go index 52d91c0118..8d5053977f 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/layer3/layer3.go +++ b/internal/acceptance/openstack/networking/v2/extensions/layer3/layer3.go @@ -92,7 +92,7 @@ func CreatePortForwarding(t *testing.T, client *gophercloud.ServiceClient, fipID t.Logf("Created Port Forwarding.") - th.AssertEquals(t, pf.Protocol, "tcp") + th.AssertEquals(t, "tcp", pf.Protocol) return pf, err } @@ -121,7 +121,7 @@ func CreatePortRangeForwarding(t *testing.T, client *gophercloud.ServiceClient, t.Logf("Created Port Range Forwarding.") - th.AssertEquals(t, pf.Protocol, "tcp") + th.AssertEquals(t, "tcp", pf.Protocol) return pf, err } diff --git a/internal/acceptance/openstack/networking/v2/extensions/layer3/portforwardings_test.go b/internal/acceptance/openstack/networking/v2/extensions/layer3/portforwardings_test.go index e6ba659068..ad99ffff38 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/layer3/portforwardings_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/layer3/portforwardings_test.go @@ -56,13 +56,13 @@ func TestLayer3PortForwardingsCreateDelete(t *testing.T) { pf, err := CreatePortForwarding(t, client, fip.ID, port.ID, port.FixedIPs) th.AssertNoErr(t, err) - th.AssertEquals(t, pf.Description, "Test description") + th.AssertEquals(t, "Test description", pf.Description) defer DeletePortForwarding(t, client, fip.ID, pf.ID) tools.PrintResource(t, pf) pfRange, err := CreatePortRangeForwarding(t, client, fip.ID, port.ID, port.FixedIPs) th.AssertNoErr(t, err) - th.AssertEquals(t, pfRange.Description, "Test description range") + th.AssertEquals(t, "Test description range", pfRange.Description) defer DeletePortForwarding(t, client, fip.ID, pfRange.ID) tools.PrintResource(t, pfRange) @@ -82,7 +82,7 @@ func TestLayer3PortForwardingsCreateDelete(t *testing.T) { newPf, err = portforwarding.Get(context.TODO(), client, fip.ID, pf.ID).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, newPf.Description, "") + th.AssertEquals(t, "", newPf.Description) // Test updating port range newRangePf, err := portforwarding.Get(context.TODO(), client, fip.ID, pfRange.ID).Extract() @@ -100,10 +100,10 @@ func TestLayer3PortForwardingsCreateDelete(t *testing.T) { newRangePf, err = portforwarding.Get(context.TODO(), client, fip.ID, pfRange.ID).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, newRangePf.Description, "") - th.AssertEquals(t, newRangePf.Protocol, "tcp") - th.AssertEquals(t, newRangePf.InternalPortRange, "1300:1399") - th.AssertEquals(t, newRangePf.ExternalPortRange, "1300:1399") + th.AssertEquals(t, "", newRangePf.Description) + th.AssertEquals(t, "tcp", newRangePf.Protocol) + th.AssertEquals(t, "1300:1399", newRangePf.InternalPortRange) + th.AssertEquals(t, "1300:1399", newRangePf.ExternalPortRange) allPages, err := portforwarding.List(client, portforwarding.ListOpts{}, fip.ID).AllPages(context.TODO()) th.AssertNoErr(t, err) diff --git a/internal/acceptance/openstack/networking/v2/extensions/layer3/routers_test.go b/internal/acceptance/openstack/networking/v2/extensions/layer3/routers_test.go index e6519472c6..c751abcfb4 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/layer3/routers_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/layer3/routers_test.go @@ -59,7 +59,7 @@ func TestLayer3RouterCreateDelete(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestLayer3ExternalRouterCreateDelete(t *testing.T) { @@ -124,7 +124,7 @@ func TestLayer3ExternalRouterCreateDelete(t *testing.T) { newRouter, err = routers.Update(context.TODO(), client, router.ID, updateOpts).Extract() th.AssertNoErr(t, err) - th.AssertDeepEquals(t, newRouter.GatewayInfo, routers.GatewayInfo{}) + th.AssertDeepEquals(t, routers.GatewayInfo{}, newRouter.GatewayInfo) } @@ -212,7 +212,7 @@ func TestLayer3RouterAgents(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestLayer3RouterRevision(t *testing.T) { diff --git a/internal/acceptance/openstack/networking/v2/extensions/qos/policies/policies_test.go b/internal/acceptance/openstack/networking/v2/extensions/qos/policies/policies_test.go index 9ee2304c75..04b244fd19 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/qos/policies/policies_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/qos/policies/policies_test.go @@ -58,7 +58,7 @@ func TestPoliciesCRUD(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestPoliciesRevision(t *testing.T) { diff --git a/internal/acceptance/openstack/networking/v2/extensions/qos/rules/rules_test.go b/internal/acceptance/openstack/networking/v2/extensions/qos/rules/rules_test.go index 811e798862..d5b80f78e8 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/qos/rules/rules_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/qos/rules/rules_test.go @@ -43,7 +43,7 @@ func TestBandwidthLimitRulesCRUD(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, newRule) - th.AssertEquals(t, newRule.MaxBurstKBps, 0) + th.AssertEquals(t, 0, newRule.MaxBurstKBps) allPages, err := rules.ListBandwidthLimitRules(client, policy.ID, rules.BandwidthLimitRulesListOpts{}).AllPages(context.TODO()) th.AssertNoErr(t, err) @@ -58,7 +58,7 @@ func TestBandwidthLimitRulesCRUD(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestDSCPMarkingRulesCRUD(t *testing.T) { @@ -89,7 +89,7 @@ func TestDSCPMarkingRulesCRUD(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, newRule) - th.AssertEquals(t, newRule.DSCPMark, 20) + th.AssertEquals(t, 20, newRule.DSCPMark) allPages, err := rules.ListDSCPMarkingRules(client, policy.ID, rules.DSCPMarkingRulesListOpts{}).AllPages(context.TODO()) th.AssertNoErr(t, err) @@ -104,7 +104,7 @@ func TestDSCPMarkingRulesCRUD(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestMinimumBandwidthRulesCRUD(t *testing.T) { @@ -135,7 +135,7 @@ func TestMinimumBandwidthRulesCRUD(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, newRule) - th.AssertEquals(t, newRule.MinKBps, 500) + th.AssertEquals(t, 500, newRule.MinKBps) allPages, err := rules.ListMinimumBandwidthRules(client, policy.ID, rules.MinimumBandwidthRulesListOpts{}).AllPages(context.TODO()) th.AssertNoErr(t, err) @@ -150,5 +150,5 @@ func TestMinimumBandwidthRulesCRUD(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } diff --git a/internal/acceptance/openstack/networking/v2/extensions/security_test.go b/internal/acceptance/openstack/networking/v2/extensions/security_test.go index 85b0a81edb..526b2fb2be 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/security_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/security_test.go @@ -22,7 +22,7 @@ func TestSecurityGroupsCreateUpdateDelete(t *testing.T) { group, err := CreateSecurityGroup(t, client) th.AssertNoErr(t, err) defer DeleteSecurityGroup(t, client, group.ID) - th.AssertEquals(t, group.Stateful, true) + th.AssertEquals(t, true, group.Stateful) rule, err := CreateSecurityGroupRule(t, client, group.ID) th.AssertNoErr(t, err) @@ -50,7 +50,7 @@ func TestSecurityGroupsCreateUpdateDelete(t *testing.T) { tools.PrintResource(t, newGroup) th.AssertEquals(t, newGroup.Name, name) th.AssertEquals(t, newGroup.Description, description) - th.AssertEquals(t, newGroup.Stateful, false) + th.AssertEquals(t, false, newGroup.Stateful) listOpts := groups.ListOpts{} allPages, err := groups.List(client, listOpts).AllPages(context.TODO()) @@ -66,7 +66,7 @@ func TestSecurityGroupsCreateUpdateDelete(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestSecurityGroupsPort(t *testing.T) { @@ -153,7 +153,7 @@ func TestSecurityGroupsRevision(t *testing.T) { tools.PrintResource(t, group) - th.AssertEquals(t, group.Name, "") + th.AssertEquals(t, "", group.Name) th.AssertEquals(t, group.Description, newDescription) } diff --git a/internal/acceptance/openstack/networking/v2/extensions/segments/segments.go b/internal/acceptance/openstack/networking/v2/extensions/segments/segments.go index e7f9c6ccad..68826ede10 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/segments/segments.go +++ b/internal/acceptance/openstack/networking/v2/extensions/segments/segments.go @@ -30,7 +30,7 @@ func CreateSegment(t *testing.T, client *gophercloud.ServiceClient, networkID st th.AssertEquals(t, segment.Name, name) th.AssertEquals(t, segment.Description, desc) - th.AssertEquals(t, segment.NetworkType, "geneve") + th.AssertEquals(t, "geneve", segment.NetworkType) th.AssertEquals(t, segment.NetworkID, networkID) return segment, nil diff --git a/internal/acceptance/openstack/networking/v2/extensions/subnetpools/subnetpools_test.go b/internal/acceptance/openstack/networking/v2/extensions/subnetpools/subnetpools_test.go index 8c9cb3120b..6f148e132f 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/subnetpools/subnetpools_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/subnetpools/subnetpools_test.go @@ -54,7 +54,7 @@ func TestSubnetPoolsCRUD(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestSubnetPoolsRevision(t *testing.T) { diff --git a/internal/acceptance/openstack/networking/v2/extensions/vlantransparent/vlantransparent_test.go b/internal/acceptance/openstack/networking/v2/extensions/vlantransparent/vlantransparent_test.go index 25adfef7ed..bf4b3d4a0f 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/vlantransparent/vlantransparent_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/vlantransparent/vlantransparent_test.go @@ -38,5 +38,5 @@ func TestVLANTransparentCRUD(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } diff --git a/internal/acceptance/openstack/networking/v2/networking.go b/internal/acceptance/openstack/networking/v2/networking.go index 6b1d2ef2b7..9147c3f13b 100644 --- a/internal/acceptance/openstack/networking/v2/networking.go +++ b/internal/acceptance/openstack/networking/v2/networking.go @@ -426,7 +426,7 @@ func CreateSubnetWithNoGateway(t *testing.T, client *gophercloud.ServiceClient, t.Logf("Successfully created subnet.") th.AssertEquals(t, subnet.Name, subnetName) - th.AssertEquals(t, subnet.GatewayIP, "") + th.AssertEquals(t, "", subnet.GatewayIP) th.AssertEquals(t, subnet.CIDR, subnetCIDR) return subnet, nil diff --git a/internal/acceptance/openstack/networking/v2/networks_test.go b/internal/acceptance/openstack/networking/v2/networks_test.go index a3e3928590..5ca5019aa2 100644 --- a/internal/acceptance/openstack/networking/v2/networks_test.go +++ b/internal/acceptance/openstack/networking/v2/networks_test.go @@ -51,7 +51,7 @@ func TestNetworksExternalList(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) iFalse := false networkListOpts = networks.ListOpts{ @@ -67,7 +67,7 @@ func TestNetworksExternalList(t *testing.T) { v, err := networks.ExtractNetworks(allPages) th.AssertNoErr(t, err) - th.AssertEquals(t, len(v), 0) + th.AssertEquals(t, 0, len(v)) } func TestNetworksCRUD(t *testing.T) { @@ -118,7 +118,7 @@ func TestNetworksCRUD(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestNetworksPortSecurityCRUD(t *testing.T) { diff --git a/internal/acceptance/openstack/networking/v2/ports_test.go b/internal/acceptance/openstack/networking/v2/ports_test.go index 1506e4f8d6..e2a385e529 100644 --- a/internal/acceptance/openstack/networking/v2/ports_test.go +++ b/internal/acceptance/openstack/networking/v2/ports_test.go @@ -74,7 +74,7 @@ func TestPortsCRUD(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) ipAddress := port.FixedIPs[0].IPAddress t.Logf("Port has IP address: %s", ipAddress) diff --git a/internal/acceptance/openstack/networking/v2/subnets_test.go b/internal/acceptance/openstack/networking/v2/subnets_test.go index de58dc73f0..e5f5cbf6b2 100644 --- a/internal/acceptance/openstack/networking/v2/subnets_test.go +++ b/internal/acceptance/openstack/networking/v2/subnets_test.go @@ -62,7 +62,7 @@ func TestSubnetCRUD(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } func TestSubnetsServiceType(t *testing.T) { @@ -275,7 +275,7 @@ func TestSubnetDNSNameservers(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, newSubnet) - th.AssertEquals(t, len(newSubnet.DNSNameservers), 1) + th.AssertEquals(t, 1, len(newSubnet.DNSNameservers)) // Update Subnet again dnsNameservers = []string{} @@ -290,7 +290,7 @@ func TestSubnetDNSNameservers(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, newSubnet) - th.AssertEquals(t, len(newSubnet.DNSNameservers), 0) + th.AssertEquals(t, 0, len(newSubnet.DNSNameservers)) } func TestSubnetsRevision(t *testing.T) { diff --git a/internal/acceptance/openstack/objectstorage/v1/objects_test.go b/internal/acceptance/openstack/objectstorage/v1/objects_test.go index 90753baeb8..fa2d80b579 100644 --- a/internal/acceptance/openstack/objectstorage/v1/objects_test.go +++ b/internal/acceptance/openstack/objectstorage/v1/objects_test.go @@ -428,5 +428,5 @@ func TestObjectsBulkDelete(t *testing.T) { t.Fatal(err) } - th.AssertEquals(t, len(allObjects), 0) + th.AssertEquals(t, 0, len(allObjects)) } diff --git a/internal/acceptance/openstack/orchestration/v1/stackevents_test.go b/internal/acceptance/openstack/orchestration/v1/stackevents_test.go index 66632321dc..61befec9ee 100644 --- a/internal/acceptance/openstack/orchestration/v1/stackevents_test.go +++ b/internal/acceptance/openstack/orchestration/v1/stackevents_test.go @@ -24,7 +24,7 @@ func TestStackEvents(t *testing.T) { allEvents, err := stackevents.ExtractEvents(allPages) th.AssertNoErr(t, err) - th.AssertEquals(t, len(allEvents), 4) + th.AssertEquals(t, 4, len(allEvents)) /* allPages is currently broke diff --git a/internal/acceptance/openstack/orchestration/v1/stackresources_test.go b/internal/acceptance/openstack/orchestration/v1/stackresources_test.go index 1e47f789b8..8e870050e0 100644 --- a/internal/acceptance/openstack/orchestration/v1/stackresources_test.go +++ b/internal/acceptance/openstack/orchestration/v1/stackresources_test.go @@ -53,5 +53,5 @@ func TestStackResources(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } diff --git a/internal/acceptance/openstack/orchestration/v1/stacks_test.go b/internal/acceptance/openstack/orchestration/v1/stacks_test.go index 56bb779f9b..2dae18badb 100644 --- a/internal/acceptance/openstack/orchestration/v1/stacks_test.go +++ b/internal/acceptance/openstack/orchestration/v1/stacks_test.go @@ -48,5 +48,5 @@ func TestStacksCRUD(t *testing.T) { } } - th.AssertEquals(t, found, true) + th.AssertEquals(t, true, found) } diff --git a/internal/acceptance/openstack/sharedfilesystems/v2/services_test.go b/internal/acceptance/openstack/sharedfilesystems/v2/services_test.go index e9a80f8675..8908c81a06 100644 --- a/internal/acceptance/openstack/sharedfilesystems/v2/services_test.go +++ b/internal/acceptance/openstack/sharedfilesystems/v2/services_test.go @@ -27,6 +27,6 @@ func TestServicesList(t *testing.T) { for _, s := range allServices { tools.PrintResource(t, &s) - th.AssertEquals(t, s.Status, "enabled") + th.AssertEquals(t, "enabled", s.Status) } } diff --git a/internal/acceptance/openstack/sharedfilesystems/v2/sharetransfers_test.go b/internal/acceptance/openstack/sharedfilesystems/v2/sharetransfers_test.go index 296b7ca807..41601621ca 100644 --- a/internal/acceptance/openstack/sharedfilesystems/v2/sharetransfers_test.go +++ b/internal/acceptance/openstack/sharedfilesystems/v2/sharetransfers_test.go @@ -53,13 +53,13 @@ func TestTransferRequestCRUD(t *testing.T) { foundRequest = true } } - th.AssertEquals(t, foundRequest, true) + th.AssertEquals(t, true, foundRequest) // checking get tr, err := sharetransfers.Get(context.TODO(), client, transferRequest.ID).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, transferRequest.ID == tr.ID, true) + th.AssertEquals(t, true, transferRequest.ID == tr.ID) // Accept Share Transfer Request err = AcceptTransfer(t, client, transferRequest) diff --git a/openstack/baremetal/v1/conductors/testing/requests_test.go b/openstack/baremetal/v1/conductors/testing/requests_test.go index 103faf579e..b85a9d77fb 100644 --- a/openstack/baremetal/v1/conductors/testing/requests_test.go +++ b/openstack/baremetal/v1/conductors/testing/requests_test.go @@ -84,7 +84,7 @@ func TestListOpts(t *testing.T) { } _, err := optsDetail.ToConductorListQuery() - th.AssertEquals(t, err.Error(), "cannot have both fields and detail options for conductors") + th.AssertEquals(t, "cannot have both fields and detail options for conductors", err.Error()) // Regular ListOpts can query, err := opts.ToConductorListQuery() diff --git a/openstack/baremetal/v1/nodes/testing/requests_test.go b/openstack/baremetal/v1/nodes/testing/requests_test.go index c881cfba80..be1ce0ed64 100644 --- a/openstack/baremetal/v1/nodes/testing/requests_test.go +++ b/openstack/baremetal/v1/nodes/testing/requests_test.go @@ -81,7 +81,7 @@ func TestListOpts(t *testing.T) { } _, err := opts.ToNodeListDetailQuery() - th.AssertEquals(t, err.Error(), "fields is not a valid option when getting a detailed listing of nodes") + th.AssertEquals(t, "fields is not a valid option when getting a detailed listing of nodes", err.Error()) // Regular ListOpts can query, err := opts.ToNodeListQuery() @@ -627,7 +627,7 @@ func TestListBIOSSettingsOpts(t *testing.T) { } _, err := opts.ToListBIOSSettingsOptsQuery() - th.AssertEquals(t, err.Error(), "cannot have both fields and detail options for BIOS settings") + th.AssertEquals(t, "cannot have both fields and detail options for BIOS settings", err.Error()) } func TestGetVendorPassthruMethods(t *testing.T) { @@ -938,5 +938,5 @@ func TestVirtualInterfaceOptsValidation(t *testing.T) { } _, err := opts.ToVirtualInterfaceMap() - th.AssertEquals(t, err.Error(), "cannot specify both port_uuid and portgroup_uuid") + th.AssertEquals(t, "cannot specify both port_uuid and portgroup_uuid", err.Error()) } diff --git a/openstack/baremetal/v1/ports/testing/requests_test.go b/openstack/baremetal/v1/ports/testing/requests_test.go index 1d335c24d9..befb02e41c 100644 --- a/openstack/baremetal/v1/ports/testing/requests_test.go +++ b/openstack/baremetal/v1/ports/testing/requests_test.go @@ -77,7 +77,7 @@ func TestListOpts(t *testing.T) { } _, err := opts.ToPortListDetailQuery() - th.AssertEquals(t, err.Error(), "fields is not a valid option when getting a detailed listing of ports") + th.AssertEquals(t, "fields is not a valid option when getting a detailed listing of ports", err.Error()) // Regular ListOpts can query, err := opts.ToPortListQuery() diff --git a/openstack/baremetalintrospection/v1/introspection/testing/results_test.go b/openstack/baremetalintrospection/v1/introspection/testing/results_test.go index da75e49190..9463ddb6f0 100644 --- a/openstack/baremetalintrospection/v1/introspection/testing/results_test.go +++ b/openstack/baremetalintrospection/v1/introspection/testing/results_test.go @@ -15,5 +15,5 @@ func TestHostnameInInventory(t *testing.T) { t.Fatalf("Failed to unmarshal Inventory data: %s", err) } - th.CheckDeepEquals(t, IntrospectionDataRes.Inventory.Hostname, "myawesomehost") + th.CheckDeepEquals(t, "myawesomehost", IntrospectionDataRes.Inventory.Hostname) } diff --git a/openstack/blockstorage/v2/backups/testing/requests_test.go b/openstack/blockstorage/v2/backups/testing/requests_test.go index 4298c6258b..fc6c2b2445 100644 --- a/openstack/blockstorage/v2/backups/testing/requests_test.go +++ b/openstack/blockstorage/v2/backups/testing/requests_test.go @@ -111,8 +111,8 @@ func TestGet(t *testing.T) { v, err := backups.Get(context.TODO(), client.ServiceClient(fakeServer), "d32019d3-bc6e-4319-9c1d-6722fc136a22").Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, v.Name, "backup-001") - th.AssertEquals(t, v.ID, "d32019d3-bc6e-4319-9c1d-6722fc136a22") + th.AssertEquals(t, "backup-001", v.Name) + th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", v.ID) } func TestCreate(t *testing.T) { @@ -125,9 +125,9 @@ func TestCreate(t *testing.T) { n, err := backups.Create(context.TODO(), client.ServiceClient(fakeServer), options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.VolumeID, "1234") - th.AssertEquals(t, n.Name, "backup-001") - th.AssertEquals(t, n.ID, "d32019d3-bc6e-4319-9c1d-6722fc136a22") + th.AssertEquals(t, "1234", n.VolumeID) + th.AssertEquals(t, "backup-001", n.Name) + th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", n.ID) } func TestRestore(t *testing.T) { @@ -140,9 +140,9 @@ func TestRestore(t *testing.T) { n, err := backups.RestoreFromBackup(context.TODO(), client.ServiceClient(fakeServer), "d32019d3-bc6e-4319-9c1d-6722fc136a22", options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.VolumeID, "1234") - th.AssertEquals(t, n.VolumeName, "vol-001") - th.AssertEquals(t, n.BackupID, "d32019d3-bc6e-4319-9c1d-6722fc136a22") + th.AssertEquals(t, "1234", n.VolumeID) + th.AssertEquals(t, "vol-001", n.VolumeName) + th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", n.BackupID) } func TestDelete(t *testing.T) { @@ -164,7 +164,7 @@ func TestExport(t *testing.T) { n, err := backups.Export(context.TODO(), client.ServiceClient(fakeServer), "d32019d3-bc6e-4319-9c1d-6722fc136a22").Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.BackupService, "cinder.backup.drivers.swift.SwiftBackupDriver") + th.AssertEquals(t, "cinder.backup.drivers.swift.SwiftBackupDriver", n.BackupService) th.AssertDeepEquals(t, n.BackupURL, backupURL) tmp := backups.ImportBackup{} @@ -186,7 +186,7 @@ func TestImport(t *testing.T) { n, err := backups.Import(context.TODO(), client.ServiceClient(fakeServer), options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.ID, "d32019d3-bc6e-4319-9c1d-6722fc136a22") + th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", n.ID) } func TestResetStatus(t *testing.T) { diff --git a/openstack/blockstorage/v2/snapshots/testing/requests_test.go b/openstack/blockstorage/v2/snapshots/testing/requests_test.go index e3b140ce3c..7409e1f560 100644 --- a/openstack/blockstorage/v2/snapshots/testing/requests_test.go +++ b/openstack/blockstorage/v2/snapshots/testing/requests_test.go @@ -68,8 +68,8 @@ func TestGet(t *testing.T) { v, err := snapshots.Get(context.TODO(), client.ServiceClient(fakeServer), "d32019d3-bc6e-4319-9c1d-6722fc136a22").Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, v.Name, "snapshot-001") - th.AssertEquals(t, v.ID, "d32019d3-bc6e-4319-9c1d-6722fc136a22") + th.AssertEquals(t, "snapshot-001", v.Name) + th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", v.ID) } func TestCreate(t *testing.T) { @@ -82,9 +82,9 @@ func TestCreate(t *testing.T) { n, err := snapshots.Create(context.TODO(), client.ServiceClient(fakeServer), options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.VolumeID, "1234") - th.AssertEquals(t, n.Name, "snapshot-001") - th.AssertEquals(t, n.ID, "d32019d3-bc6e-4319-9c1d-6722fc136a22") + th.AssertEquals(t, "1234", n.VolumeID) + th.AssertEquals(t, "snapshot-001", n.Name) + th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", n.ID) } func TestUpdateMetadata(t *testing.T) { diff --git a/openstack/blockstorage/v2/transfers/testing/requests_test.go b/openstack/blockstorage/v2/transfers/testing/requests_test.go index f6404fb2a2..f768e5b7d5 100644 --- a/openstack/blockstorage/v2/transfers/testing/requests_test.go +++ b/openstack/blockstorage/v2/transfers/testing/requests_test.go @@ -59,7 +59,7 @@ func TestListTransfers(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestListTransfersAllPages(t *testing.T) { diff --git a/openstack/blockstorage/v2/volumes/testing/requests_test.go b/openstack/blockstorage/v2/volumes/testing/requests_test.go index 3a1819b3c5..4ffccfbbfc 100644 --- a/openstack/blockstorage/v2/volumes/testing/requests_test.go +++ b/openstack/blockstorage/v2/volumes/testing/requests_test.go @@ -193,8 +193,8 @@ func TestGet(t *testing.T) { v, err := volumes.Get(context.TODO(), client.ServiceClient(fakeServer), "d32019d3-bc6e-4319-9c1d-6722fc136a22").Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, v.Name, "vol-001") - th.AssertEquals(t, v.ID, "d32019d3-bc6e-4319-9c1d-6722fc136a22") + th.AssertEquals(t, "vol-001", v.Name) + th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", v.ID) } func TestCreate(t *testing.T) { @@ -207,8 +207,8 @@ func TestCreate(t *testing.T) { n, err := volumes.Create(context.TODO(), client.ServiceClient(fakeServer), options, nil).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.Size, 75) - th.AssertEquals(t, n.ID, "d32019d3-bc6e-4319-9c1d-6722fc136a22") + th.AssertEquals(t, 75, n.Size) + th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", n.ID) } func TestCreateSchedulerHints(t *testing.T) { diff --git a/openstack/blockstorage/v3/backups/testing/requests_test.go b/openstack/blockstorage/v3/backups/testing/requests_test.go index 76b39cb09c..7eeff49d92 100644 --- a/openstack/blockstorage/v3/backups/testing/requests_test.go +++ b/openstack/blockstorage/v3/backups/testing/requests_test.go @@ -111,8 +111,8 @@ func TestGet(t *testing.T) { v, err := backups.Get(context.TODO(), client.ServiceClient(fakeServer), "d32019d3-bc6e-4319-9c1d-6722fc136a22").Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, v.Name, "backup-001") - th.AssertEquals(t, v.ID, "d32019d3-bc6e-4319-9c1d-6722fc136a22") + th.AssertEquals(t, "backup-001", v.Name) + th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", v.ID) } func TestCreate(t *testing.T) { @@ -125,9 +125,9 @@ func TestCreate(t *testing.T) { n, err := backups.Create(context.TODO(), client.ServiceClient(fakeServer), options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.VolumeID, "1234") - th.AssertEquals(t, n.Name, "backup-001") - th.AssertEquals(t, n.ID, "d32019d3-bc6e-4319-9c1d-6722fc136a22") + th.AssertEquals(t, "1234", n.VolumeID) + th.AssertEquals(t, "backup-001", n.Name) + th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", n.ID) } func TestRestore(t *testing.T) { @@ -140,9 +140,9 @@ func TestRestore(t *testing.T) { n, err := backups.RestoreFromBackup(context.TODO(), client.ServiceClient(fakeServer), "d32019d3-bc6e-4319-9c1d-6722fc136a22", options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.VolumeID, "1234") - th.AssertEquals(t, n.VolumeName, "vol-001") - th.AssertEquals(t, n.BackupID, "d32019d3-bc6e-4319-9c1d-6722fc136a22") + th.AssertEquals(t, "1234", n.VolumeID) + th.AssertEquals(t, "vol-001", n.VolumeName) + th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", n.BackupID) } func TestDelete(t *testing.T) { @@ -164,7 +164,7 @@ func TestExport(t *testing.T) { n, err := backups.Export(context.TODO(), client.ServiceClient(fakeServer), "d32019d3-bc6e-4319-9c1d-6722fc136a22").Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.BackupService, "cinder.backup.drivers.swift.SwiftBackupDriver") + th.AssertEquals(t, "cinder.backup.drivers.swift.SwiftBackupDriver", n.BackupService) th.AssertDeepEquals(t, n.BackupURL, backupURL) tmp := backups.ImportBackup{} @@ -186,7 +186,7 @@ func TestImport(t *testing.T) { n, err := backups.Import(context.TODO(), client.ServiceClient(fakeServer), options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.ID, "d32019d3-bc6e-4319-9c1d-6722fc136a22") + th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", n.ID) } func TestResetStatus(t *testing.T) { diff --git a/openstack/blockstorage/v3/manageablevolumes/testing/requests_test.go b/openstack/blockstorage/v3/manageablevolumes/testing/requests_test.go index 7cbf0fe3f4..5c02c1a5ef 100644 --- a/openstack/blockstorage/v3/manageablevolumes/testing/requests_test.go +++ b/openstack/blockstorage/v3/manageablevolumes/testing/requests_test.go @@ -31,14 +31,14 @@ func TestManageExisting(t *testing.T) { n, err := manageablevolumes.ManageExisting(context.TODO(), client.ServiceClient(fakeServer), options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.Host, "host@lvm#LVM") - th.AssertEquals(t, n.Name, "New Volume") - th.AssertEquals(t, n.AvailabilityZone, "nova") - th.AssertEquals(t, n.Description, "Volume imported from existingLV") - th.AssertEquals(t, n.Bootable, "true") - th.AssertDeepEquals(t, n.Metadata, map[string]string{ + th.AssertEquals(t, "host@lvm#LVM", n.Host) + th.AssertEquals(t, "New Volume", n.Name) + th.AssertEquals(t, "nova", n.AvailabilityZone) + th.AssertEquals(t, "Volume imported from existingLV", n.Description) + th.AssertEquals(t, "true", n.Bootable) + th.AssertDeepEquals(t, map[string]string{ "key1": "value1", "key2": "value2", - }) - th.AssertEquals(t, n.ID, "23cf872b-c781-4cd4-847d-5f2ec8cbd91c") + }, n.Metadata) + th.AssertEquals(t, "23cf872b-c781-4cd4-847d-5f2ec8cbd91c", n.ID) } diff --git a/openstack/blockstorage/v3/snapshots/testing/requests_test.go b/openstack/blockstorage/v3/snapshots/testing/requests_test.go index fb7a6d3196..64e61b608b 100644 --- a/openstack/blockstorage/v3/snapshots/testing/requests_test.go +++ b/openstack/blockstorage/v3/snapshots/testing/requests_test.go @@ -124,8 +124,8 @@ func TestGet(t *testing.T) { v, err := snapshots.Get(context.TODO(), client.ServiceClient(fakeServer), "d32019d3-bc6e-4319-9c1d-6722fc136a22").Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, v.Name, "snapshot-001") - th.AssertEquals(t, v.ID, "d32019d3-bc6e-4319-9c1d-6722fc136a22") + th.AssertEquals(t, "snapshot-001", v.Name) + th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", v.ID) } func TestCreate(t *testing.T) { @@ -138,9 +138,9 @@ func TestCreate(t *testing.T) { n, err := snapshots.Create(context.TODO(), client.ServiceClient(fakeServer), options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.VolumeID, "1234") - th.AssertEquals(t, n.Name, "snapshot-001") - th.AssertEquals(t, n.ID, "d32019d3-bc6e-4319-9c1d-6722fc136a22") + th.AssertEquals(t, "1234", n.VolumeID) + th.AssertEquals(t, "snapshot-001", n.Name) + th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", n.ID) } func TestUpdateMetadata(t *testing.T) { diff --git a/openstack/blockstorage/v3/transfers/testing/requests_test.go b/openstack/blockstorage/v3/transfers/testing/requests_test.go index 5b5428e1f4..d1065bdef0 100644 --- a/openstack/blockstorage/v3/transfers/testing/requests_test.go +++ b/openstack/blockstorage/v3/transfers/testing/requests_test.go @@ -59,7 +59,7 @@ func TestListTransfers(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestListTransfersAllPages(t *testing.T) { diff --git a/openstack/blockstorage/v3/volumes/testing/requests_test.go b/openstack/blockstorage/v3/volumes/testing/requests_test.go index 5bd49594fc..145fb0ed29 100644 --- a/openstack/blockstorage/v3/volumes/testing/requests_test.go +++ b/openstack/blockstorage/v3/volumes/testing/requests_test.go @@ -197,8 +197,8 @@ func TestGet(t *testing.T) { v, err := volumes.Get(context.TODO(), client.ServiceClient(fakeServer), "d32019d3-bc6e-4319-9c1d-6722fc136a22").Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, v.Name, "vol-001") - th.AssertEquals(t, v.ID, "d32019d3-bc6e-4319-9c1d-6722fc136a22") + th.AssertEquals(t, "vol-001", v.Name) + th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", v.ID) } func TestCreate(t *testing.T) { @@ -211,8 +211,8 @@ func TestCreate(t *testing.T) { n, err := volumes.Create(context.TODO(), client.ServiceClient(fakeServer), options, nil).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.Size, 75) - th.AssertEquals(t, n.ID, "d32019d3-bc6e-4319-9c1d-6722fc136a22") + th.AssertEquals(t, 75, n.Size) + th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", n.ID) } func TestCreateSchedulerHints(t *testing.T) { @@ -303,9 +303,9 @@ func TestCreateFromBackup(t *testing.T) { v, err := volumes.Create(context.TODO(), client.ServiceClient(fakeServer), options, nil).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, v.Size, 30) - th.AssertEquals(t, v.ID, "d32019d3-bc6e-4319-9c1d-6722fc136a22") - th.AssertEquals(t, *v.BackupID, "20c792f0-bb03-434f-b653-06ef238e337e") + th.AssertEquals(t, 30, v.Size) + th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", v.ID) + th.AssertEquals(t, "20c792f0-bb03-434f-b653-06ef238e337e", *v.BackupID) } func TestAttach(t *testing.T) { diff --git a/openstack/blockstorage/v3/volumetypes/testing/requests_test.go b/openstack/blockstorage/v3/volumetypes/testing/requests_test.go index b64a269c59..c3410c0420 100644 --- a/openstack/blockstorage/v3/volumetypes/testing/requests_test.go +++ b/openstack/blockstorage/v3/volumetypes/testing/requests_test.go @@ -48,7 +48,7 @@ func TestListAll(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.AssertEquals(t, pages, 1) + th.AssertEquals(t, 1, pages) } func TestGet(t *testing.T) { @@ -60,11 +60,11 @@ func TestGet(t *testing.T) { v, err := volumetypes.Get(context.TODO(), client.ServiceClient(fakeServer), "d32019d3-bc6e-4319-9c1d-6722fc136a22").Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, v.Name, "vol-type-001") - th.AssertEquals(t, v.ID, "d32019d3-bc6e-4319-9c1d-6722fc136a22") - th.AssertEquals(t, v.ExtraSpecs["capabilities"], "gpu") - th.AssertEquals(t, v.QosSpecID, "d32019d3-bc6e-4319-9c1d-6722fc136a22") - th.AssertEquals(t, v.PublicAccess, true) + th.AssertEquals(t, "vol-type-001", v.Name) + th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", v.ID) + th.AssertEquals(t, "gpu", v.ExtraSpecs["capabilities"]) + th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", v.QosSpecID) + th.AssertEquals(t, true, v.PublicAccess) } func TestCreate(t *testing.T) { @@ -85,12 +85,12 @@ func TestCreate(t *testing.T) { n, err := volumetypes.Create(context.TODO(), client.ServiceClient(fakeServer), options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.Name, "test_type") - th.AssertEquals(t, n.Description, "test_type_desc") - th.AssertEquals(t, n.IsPublic, true) - th.AssertEquals(t, n.PublicAccess, true) - th.AssertEquals(t, n.ID, "6d0ff92a-0007-4780-9ece-acfe5876966a") - th.AssertEquals(t, n.ExtraSpecs["capabilities"], "gpu") + th.AssertEquals(t, "test_type", n.Name) + th.AssertEquals(t, "test_type_desc", n.Description) + th.AssertEquals(t, true, n.IsPublic) + th.AssertEquals(t, true, n.PublicAccess) + th.AssertEquals(t, "6d0ff92a-0007-4780-9ece-acfe5876966a", n.ID) + th.AssertEquals(t, "gpu", n.ExtraSpecs["capabilities"]) } func TestDelete(t *testing.T) { diff --git a/openstack/compute/apiversions/testing/requests_test.go b/openstack/compute/apiversions/testing/requests_test.go index 59d05b9eb2..9b58a2602b 100644 --- a/openstack/compute/apiversions/testing/requests_test.go +++ b/openstack/compute/apiversions/testing/requests_test.go @@ -43,5 +43,5 @@ func TestGetMultipleAPIVersion(t *testing.T) { MockGetMultipleResponses(t, fakeServer) _, err := apiversions.Get(context.TODO(), client.ServiceClient(fakeServer), "v3").Extract() - th.AssertEquals(t, err.Error(), "Unable to find requested API version") + th.AssertEquals(t, "Unable to find requested API version", err.Error()) } diff --git a/openstack/compute/v2/extensions/testing/delegate_test.go b/openstack/compute/v2/extensions/testing/delegate_test.go index 4461b7464f..8815b7427e 100644 --- a/openstack/compute/v2/extensions/testing/delegate_test.go +++ b/openstack/compute/v2/extensions/testing/delegate_test.go @@ -50,9 +50,9 @@ func TestGet(t *testing.T) { ext, err := extensions.Get(context.TODO(), client.ServiceClient(fakeServer), "agent").Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, ext.Updated, "2013-02-03T10:00:00-00:00") - th.AssertEquals(t, ext.Name, "agent") - th.AssertEquals(t, ext.Namespace, "http://docs.openstack.org/ext/agent/api/v2.0") - th.AssertEquals(t, ext.Alias, "agent") - th.AssertEquals(t, ext.Description, "The agent management extension.") + th.AssertEquals(t, "2013-02-03T10:00:00-00:00", ext.Updated) + th.AssertEquals(t, "agent", ext.Name) + th.AssertEquals(t, "http://docs.openstack.org/ext/agent/api/v2.0", ext.Namespace) + th.AssertEquals(t, "agent", ext.Alias) + th.AssertEquals(t, "The agent management extension.", ext.Description) } diff --git a/openstack/compute/v2/keypairs/testing/fixtures_test.go b/openstack/compute/v2/keypairs/testing/fixtures_test.go index 27dc933992..ae61082cda 100644 --- a/openstack/compute/v2/keypairs/testing/fixtures_test.go +++ b/openstack/compute/v2/keypairs/testing/fixtures_test.go @@ -231,7 +231,7 @@ func HandleDeleteSuccessfully(t *testing.T, fakeServer th.FakeServer) { fakeServer.Mux.HandleFunc("/os-keypairs/deletedkey", func(w http.ResponseWriter, r *http.Request) { th.TestMethod(t, r, "DELETE") th.TestHeader(t, r, "X-Auth-Token", client.TokenID) - th.AssertEquals(t, r.Form.Get("user_id"), "") + th.AssertEquals(t, "", r.Form.Get("user_id")) w.WriteHeader(http.StatusAccepted) }) diff --git a/openstack/compute/v2/remoteconsoles/testing/requests_test.go b/openstack/compute/v2/remoteconsoles/testing/requests_test.go index 0ae0f480d9..1ef52873da 100644 --- a/openstack/compute/v2/remoteconsoles/testing/requests_test.go +++ b/openstack/compute/v2/remoteconsoles/testing/requests_test.go @@ -37,5 +37,5 @@ func TestCreate(t *testing.T) { th.AssertEquals(t, s.Protocol, string(remoteconsoles.ConsoleProtocolVNC)) th.AssertEquals(t, s.Type, string(remoteconsoles.ConsoleTypeNoVNC)) - th.AssertEquals(t, s.URL, "http://192.168.0.4:6080/vnc_auto.html?token=9a2372b9-6a0e-4f71-aca1-56020e6bb677") + th.AssertEquals(t, "http://192.168.0.4:6080/vnc_auto.html?token=9a2372b9-6a0e-4f71-aca1-56020e6bb677", s.URL) } diff --git a/openstack/compute/v2/servers/testing/results_test.go b/openstack/compute/v2/servers/testing/results_test.go index ba58d63e0c..5c7711bdb3 100644 --- a/openstack/compute/v2/servers/testing/results_test.go +++ b/openstack/compute/v2/servers/testing/results_test.go @@ -26,7 +26,7 @@ func TestExtractPassword_no_pwd_data(t *testing.T) { pwd, err := resp.ExtractPassword(nil) th.AssertNoErr(t, err) - th.AssertEquals(t, pwd, "") + th.AssertEquals(t, "", pwd) } // Ok - return encrypted password when no private key is given. diff --git a/openstack/compute/v2/usage/testing/requests_test.go b/openstack/compute/v2/usage/testing/requests_test.go index eb1692266f..f2697412b4 100644 --- a/openstack/compute/v2/usage/testing/requests_test.go +++ b/openstack/compute/v2/usage/testing/requests_test.go @@ -26,7 +26,7 @@ func TestGetTenant(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.AssertEquals(t, count, 1) + th.AssertEquals(t, 1, count) } func TestAllTenants(t *testing.T) { @@ -49,5 +49,5 @@ func TestAllTenants(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.AssertEquals(t, count, 1) + th.AssertEquals(t, 1, count) } diff --git a/openstack/db/v1/configurations/testing/requests_test.go b/openstack/db/v1/configurations/testing/requests_test.go index 11e14ebfb1..6c8d9f599f 100644 --- a/openstack/db/v1/configurations/testing/requests_test.go +++ b/openstack/db/v1/configurations/testing/requests_test.go @@ -138,7 +138,7 @@ func TestListInstances(t *testing.T) { return false, err } - th.AssertDeepEquals(t, actual, []instances.Instance{expectedInstance}) + th.AssertDeepEquals(t, []instances.Instance{expectedInstance}, actual) return true, nil }) diff --git a/openstack/dns/v2/zones/testing/requests_test.go b/openstack/dns/v2/zones/testing/requests_test.go index fcc1838ce3..f425f051b8 100644 --- a/openstack/dns/v2/zones/testing/requests_test.go +++ b/openstack/dns/v2/zones/testing/requests_test.go @@ -115,7 +115,7 @@ func TestShare(t *testing.T) { defer fakeServer.Teardown() fakeServer.Mux.HandleFunc("/zones/zone-id/shares", func(w http.ResponseWriter, r *http.Request) { - th.AssertEquals(t, r.Method, "POST") + th.AssertEquals(t, "POST", r.Method) body, err := io.ReadAll(r.Body) defer r.Body.Close() @@ -143,7 +143,7 @@ func TestUnshare(t *testing.T) { defer fakeServer.Teardown() fakeServer.Mux.HandleFunc("/zones/zone-id/shares/share-id", func(w http.ResponseWriter, r *http.Request) { - th.AssertEquals(t, r.Method, "DELETE") + th.AssertEquals(t, "DELETE", r.Method) w.WriteHeader(http.StatusNoContent) }) @@ -156,7 +156,7 @@ func TestListShares(t *testing.T) { defer fakeServer.Teardown() fakeServer.Mux.HandleFunc("/zones/zone-id/shares", func(w http.ResponseWriter, r *http.Request) { - th.AssertEquals(t, r.Method, "GET") + th.AssertEquals(t, "GET", r.Method) th.AssertEquals(t, "true", r.Header.Get("X-Auth-All-Projects")) w.Header().Add("Content-Type", "application/json") diff --git a/openstack/identity/v2/tenants/testing/requests_test.go b/openstack/identity/v2/tenants/testing/requests_test.go index d658d37286..feb3bc19a6 100644 --- a/openstack/identity/v2/tenants/testing/requests_test.go +++ b/openstack/identity/v2/tenants/testing/requests_test.go @@ -28,7 +28,7 @@ func TestListTenants(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestCreateTenant(t *testing.T) { diff --git a/openstack/identity/v3/applicationcredentials/testing/requests_test.go b/openstack/identity/v3/applicationcredentials/testing/requests_test.go index d31b183c2b..b992e79146 100644 --- a/openstack/identity/v3/applicationcredentials/testing/requests_test.go +++ b/openstack/identity/v3/applicationcredentials/testing/requests_test.go @@ -27,7 +27,7 @@ func TestListApplicationCredentials(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestListApplicationCredentialsAllPages(t *testing.T) { @@ -40,8 +40,8 @@ func TestListApplicationCredentialsAllPages(t *testing.T) { actual, err := applicationcredentials.ExtractApplicationCredentials(allPages) th.AssertNoErr(t, err) th.CheckDeepEquals(t, ExpectedApplicationCredentialsSlice, actual) - th.AssertDeepEquals(t, ExpectedApplicationCredentialsSlice[0].Roles, []applicationcredentials.Role{{ID: "31f87923ae4a4d119aa0b85dcdbeed13", Name: "compute_viewer"}}) - th.AssertDeepEquals(t, ExpectedApplicationCredentialsSlice[1].Roles, []applicationcredentials.Role{{ID: "31f87923ae4a4d119aa0b85dcdbeed13", Name: "compute_viewer"}, {ID: "4494bc5bea1a4105ad7fbba6a7eb9ef4", Name: "network_viewer"}}) + th.AssertDeepEquals(t, []applicationcredentials.Role{{ID: "31f87923ae4a4d119aa0b85dcdbeed13", Name: "compute_viewer"}}, ExpectedApplicationCredentialsSlice[0].Roles) + th.AssertDeepEquals(t, []applicationcredentials.Role{{ID: "31f87923ae4a4d119aa0b85dcdbeed13", Name: "compute_viewer"}, {ID: "4494bc5bea1a4105ad7fbba6a7eb9ef4", Name: "network_viewer"}}, ExpectedApplicationCredentialsSlice[1].Roles) } func TestGetApplicationCredential(t *testing.T) { @@ -148,7 +148,7 @@ func TestListAccessRules(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestGetAccessRule(t *testing.T) { diff --git a/openstack/identity/v3/catalog/testing/catalog_test.go b/openstack/identity/v3/catalog/testing/catalog_test.go index 5f35803ca4..65e4c1dc3d 100644 --- a/openstack/identity/v3/catalog/testing/catalog_test.go +++ b/openstack/identity/v3/catalog/testing/catalog_test.go @@ -27,5 +27,5 @@ func TestListCatalog(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } diff --git a/openstack/identity/v3/credentials/testing/requests_test.go b/openstack/identity/v3/credentials/testing/requests_test.go index 86cbe93b59..19578bc001 100644 --- a/openstack/identity/v3/credentials/testing/requests_test.go +++ b/openstack/identity/v3/credentials/testing/requests_test.go @@ -27,7 +27,7 @@ func TestListCredentials(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestListCredentialsAllPages(t *testing.T) { @@ -40,8 +40,8 @@ func TestListCredentialsAllPages(t *testing.T) { actual, err := credentials.ExtractCredentials(allPages) th.AssertNoErr(t, err) th.CheckDeepEquals(t, ExpectedCredentialsSlice, actual) - th.AssertDeepEquals(t, ExpectedCredentialsSlice[0].Blob, "{\"access\":\"181920\",\"secret\":\"secretKey\"}") - th.AssertDeepEquals(t, ExpectedCredentialsSlice[1].Blob, "{\"access\":\"7da79ff0aa364e1396f067e352b9b79a\",\"secret\":\"7a18d68ba8834b799d396f3ff6f1e98c\"}") + th.AssertDeepEquals(t, "{\"access\":\"181920\",\"secret\":\"secretKey\"}", ExpectedCredentialsSlice[0].Blob) + th.AssertDeepEquals(t, "{\"access\":\"7da79ff0aa364e1396f067e352b9b79a\",\"secret\":\"7a18d68ba8834b799d396f3ff6f1e98c\"}", ExpectedCredentialsSlice[1].Blob) } func TestGetCredential(t *testing.T) { diff --git a/openstack/identity/v3/domains/testing/requests_test.go b/openstack/identity/v3/domains/testing/requests_test.go index 00819c7882..3f070b0cbd 100644 --- a/openstack/identity/v3/domains/testing/requests_test.go +++ b/openstack/identity/v3/domains/testing/requests_test.go @@ -27,7 +27,7 @@ func TestListAvailableDomains(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestListDomains(t *testing.T) { @@ -47,7 +47,7 @@ func TestListDomains(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestListDomainsAllPages(t *testing.T) { diff --git a/openstack/identity/v3/ec2credentials/testing/requests_test.go b/openstack/identity/v3/ec2credentials/testing/requests_test.go index 1344aed51c..aa30f295e4 100644 --- a/openstack/identity/v3/ec2credentials/testing/requests_test.go +++ b/openstack/identity/v3/ec2credentials/testing/requests_test.go @@ -27,7 +27,7 @@ func TestListEC2Credentials(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestListEC2CredentialsAllPages(t *testing.T) { diff --git a/openstack/identity/v3/federation/testing/requests_test.go b/openstack/identity/v3/federation/testing/requests_test.go index 29f2db2a85..410bfe91a0 100644 --- a/openstack/identity/v3/federation/testing/requests_test.go +++ b/openstack/identity/v3/federation/testing/requests_test.go @@ -27,7 +27,7 @@ func TestListMappings(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestListMappingsAllPages(t *testing.T) { diff --git a/openstack/identity/v3/groups/testing/requests_test.go b/openstack/identity/v3/groups/testing/requests_test.go index 8117368023..017c6f1e61 100644 --- a/openstack/identity/v3/groups/testing/requests_test.go +++ b/openstack/identity/v3/groups/testing/requests_test.go @@ -27,7 +27,7 @@ func TestListGroups(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestListGroupsAllPages(t *testing.T) { @@ -40,8 +40,8 @@ func TestListGroupsAllPages(t *testing.T) { actual, err := groups.ExtractGroups(allPages) th.AssertNoErr(t, err) th.CheckDeepEquals(t, ExpectedGroupsSlice, actual) - th.AssertEquals(t, ExpectedGroupsSlice[0].Extra["email"], "support@localhost") - th.AssertEquals(t, ExpectedGroupsSlice[1].Extra["email"], "support@example.com") + th.AssertEquals(t, "support@localhost", ExpectedGroupsSlice[0].Extra["email"]) + th.AssertEquals(t, "support@example.com", ExpectedGroupsSlice[1].Extra["email"]) } func TestListGroupsFiltersCheck(t *testing.T) { @@ -85,7 +85,7 @@ func TestGetGroup(t *testing.T) { th.AssertNoErr(t, err) th.CheckDeepEquals(t, SecondGroup, *actual) - th.AssertEquals(t, SecondGroup.Extra["email"], "support@example.com") + th.AssertEquals(t, "support@example.com", SecondGroup.Extra["email"]) } func TestCreateGroup(t *testing.T) { diff --git a/openstack/identity/v3/limits/testing/requests_test.go b/openstack/identity/v3/limits/testing/requests_test.go index e1dca5f73f..22af6f8548 100644 --- a/openstack/identity/v3/limits/testing/requests_test.go +++ b/openstack/identity/v3/limits/testing/requests_test.go @@ -37,7 +37,7 @@ func TestListLimits(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestListLimitsAllPages(t *testing.T) { diff --git a/openstack/identity/v3/oauth1/testing/requests_test.go b/openstack/identity/v3/oauth1/testing/requests_test.go index 1cf2f7174f..4febcb8c07 100644 --- a/openstack/identity/v3/oauth1/testing/requests_test.go +++ b/openstack/identity/v3/oauth1/testing/requests_test.go @@ -75,7 +75,7 @@ func TestListConsumers(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestListConsumersAllPages(t *testing.T) { @@ -187,7 +187,7 @@ func TestListAccessTokens(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestListAccessTokensAllPages(t *testing.T) { @@ -219,7 +219,7 @@ func TestListAccessTokenRoles(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestListAccessTokenRolesAllPages(t *testing.T) { diff --git a/openstack/identity/v3/policies/testing/requests_test.go b/openstack/identity/v3/policies/testing/requests_test.go index e54f9703a6..2950abd327 100644 --- a/openstack/identity/v3/policies/testing/requests_test.go +++ b/openstack/identity/v3/policies/testing/requests_test.go @@ -28,7 +28,7 @@ func TestListPolicies(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestListPoliciesAllPages(t *testing.T) { diff --git a/openstack/identity/v3/projects/testing/requests_test.go b/openstack/identity/v3/projects/testing/requests_test.go index ca5bebe454..a04a64c7e4 100644 --- a/openstack/identity/v3/projects/testing/requests_test.go +++ b/openstack/identity/v3/projects/testing/requests_test.go @@ -27,7 +27,7 @@ func TestListAvailableProjects(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestListProjects(t *testing.T) { @@ -51,9 +51,9 @@ func TestListProjects(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 2) + th.CheckEquals(t, 2, count) - th.CheckEquals(t, len(actualProjects), 2) + th.CheckEquals(t, 2, len(actualProjects)) th.CheckDeepEquals(t, ExpectedProjectSlice, actualProjects) } diff --git a/openstack/identity/v3/regions/testing/requests_test.go b/openstack/identity/v3/regions/testing/requests_test.go index 0c82efd009..50a66a20d5 100644 --- a/openstack/identity/v3/regions/testing/requests_test.go +++ b/openstack/identity/v3/regions/testing/requests_test.go @@ -27,7 +27,7 @@ func TestListRegions(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestListRegionsAllPages(t *testing.T) { @@ -40,7 +40,7 @@ func TestListRegionsAllPages(t *testing.T) { actual, err := regions.ExtractRegions(allPages) th.AssertNoErr(t, err) th.CheckDeepEquals(t, ExpectedRegionsSlice, actual) - th.AssertEquals(t, ExpectedRegionsSlice[1].Extra["email"], "westsupport@example.com") + th.AssertEquals(t, "westsupport@example.com", ExpectedRegionsSlice[1].Extra["email"]) } func TestGetRegion(t *testing.T) { diff --git a/openstack/identity/v3/registeredlimits/testing/requests_test.go b/openstack/identity/v3/registeredlimits/testing/requests_test.go index a8f0e73bc7..1d31d02e0b 100644 --- a/openstack/identity/v3/registeredlimits/testing/requests_test.go +++ b/openstack/identity/v3/registeredlimits/testing/requests_test.go @@ -27,7 +27,7 @@ func TestListRegisteredLimits(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestListRegisteredLimitsAllPages(t *testing.T) { diff --git a/openstack/identity/v3/roles/testing/requests_test.go b/openstack/identity/v3/roles/testing/requests_test.go index 7ef5085904..a70ca16856 100644 --- a/openstack/identity/v3/roles/testing/requests_test.go +++ b/openstack/identity/v3/roles/testing/requests_test.go @@ -27,7 +27,7 @@ func TestListRoles(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestListRolesAllPages(t *testing.T) { @@ -40,7 +40,7 @@ func TestListRolesAllPages(t *testing.T) { actual, err := roles.ExtractRoles(allPages) th.AssertNoErr(t, err) th.CheckDeepEquals(t, ExpectedRolesSlice, actual) - th.AssertEquals(t, ExpectedRolesSlice[1].Extra["test"], "this is for the test") + th.AssertEquals(t, "this is for the test", ExpectedRolesSlice[1].Extra["test"]) } func TestListUsersFiltersCheck(t *testing.T) { @@ -171,7 +171,7 @@ func TestListAssignmentsSinglePage(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestListAssignmentsWithNamesSinglePage(t *testing.T) { @@ -195,7 +195,7 @@ func TestListAssignmentsWithNamesSinglePage(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestListAssignmentsWithSubtreeSinglePage(t *testing.T) { @@ -219,7 +219,7 @@ func TestListAssignmentsWithSubtreeSinglePage(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestListAssignmentsOnResource_ProjectsUsers(t *testing.T) { @@ -241,7 +241,7 @@ func TestListAssignmentsOnResource_ProjectsUsers(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestListAssignmentsOnResource_DomainsUsers(t *testing.T) { @@ -263,7 +263,7 @@ func TestListAssignmentsOnResource_DomainsUsers(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestListAssignmentsOnResource_ProjectsGroups(t *testing.T) { @@ -285,7 +285,7 @@ func TestListAssignmentsOnResource_ProjectsGroups(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestListAssignmentsOnResource_DomainsGroups(t *testing.T) { @@ -307,7 +307,7 @@ func TestListAssignmentsOnResource_DomainsGroups(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestAssign(t *testing.T) { diff --git a/openstack/identity/v3/services/testing/requests_test.go b/openstack/identity/v3/services/testing/requests_test.go index c88cefb322..1f1f53c720 100644 --- a/openstack/identity/v3/services/testing/requests_test.go +++ b/openstack/identity/v3/services/testing/requests_test.go @@ -47,7 +47,7 @@ func TestListServices(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestListServicesAllPages(t *testing.T) { @@ -60,8 +60,8 @@ func TestListServicesAllPages(t *testing.T) { actual, err := services.ExtractServices(allPages) th.AssertNoErr(t, err) th.CheckDeepEquals(t, ExpectedServicesSlice, actual) - th.AssertEquals(t, ExpectedServicesSlice[0].Extra["email"], "service-one@example.com") - th.AssertEquals(t, ExpectedServicesSlice[1].Extra["email"], "service@example.com") + th.AssertEquals(t, "service-one@example.com", ExpectedServicesSlice[0].Extra["email"]) + th.AssertEquals(t, "service@example.com", ExpectedServicesSlice[1].Extra["email"]) } func TestGetSuccessful(t *testing.T) { @@ -73,7 +73,7 @@ func TestGetSuccessful(t *testing.T) { th.AssertNoErr(t, err) th.CheckDeepEquals(t, SecondService, *actual) - th.AssertEquals(t, SecondService.Extra["email"], "service@example.com") + th.AssertEquals(t, "service@example.com", SecondService.Extra["email"]) } func TestUpdateSuccessful(t *testing.T) { @@ -89,7 +89,7 @@ func TestUpdateSuccessful(t *testing.T) { actual, err := services.Update(context.TODO(), client.ServiceClient(fakeServer), "9876", updateOpts).Extract() th.AssertNoErr(t, err) th.CheckDeepEquals(t, SecondServiceUpdated, *actual) - th.AssertEquals(t, SecondServiceUpdated.Description, "Service Two Updated") + th.AssertEquals(t, "Service Two Updated", SecondServiceUpdated.Description) } func TestDeleteSuccessful(t *testing.T) { diff --git a/openstack/identity/v3/trusts/testing/requests_test.go b/openstack/identity/v3/trusts/testing/requests_test.go index 8f11e92855..30bde153b4 100644 --- a/openstack/identity/v3/trusts/testing/requests_test.go +++ b/openstack/identity/v3/trusts/testing/requests_test.go @@ -90,7 +90,7 @@ func TestListTrusts(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestListTrustsAllPages(t *testing.T) { @@ -136,7 +136,7 @@ func TestListTrustRoles(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestListTrustRolesAllPages(t *testing.T) { diff --git a/openstack/identity/v3/users/testing/requests_test.go b/openstack/identity/v3/users/testing/requests_test.go index 12ed9323d7..1754d283e9 100644 --- a/openstack/identity/v3/users/testing/requests_test.go +++ b/openstack/identity/v3/users/testing/requests_test.go @@ -29,7 +29,7 @@ func TestListUsers(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestListUsersAllPages(t *testing.T) { @@ -42,8 +42,8 @@ func TestListUsersAllPages(t *testing.T) { actual, err := users.ExtractUsers(allPages) th.AssertNoErr(t, err) th.CheckDeepEquals(t, ExpectedUsersSlice, actual) - th.AssertEquals(t, ExpectedUsersSlice[0].Extra["email"], "glance@localhost") - th.AssertEquals(t, ExpectedUsersSlice[1].Extra["email"], "jsmith@example.com") + th.AssertEquals(t, "glance@localhost", ExpectedUsersSlice[0].Extra["email"]) + th.AssertEquals(t, "jsmith@example.com", ExpectedUsersSlice[1].Extra["email"]) } func TestListUsersFiltersCheck(t *testing.T) { @@ -86,7 +86,7 @@ func TestGetUser(t *testing.T) { actual, err := users.Get(context.TODO(), client.ServiceClient(fakeServer), "9fe1d3").Extract() th.AssertNoErr(t, err) th.CheckDeepEquals(t, SecondUser, *actual) - th.AssertEquals(t, SecondUser.Extra["email"], "jsmith@example.com") + th.AssertEquals(t, "jsmith@example.com", SecondUser.Extra["email"]) } func TestCreateUser(t *testing.T) { diff --git a/openstack/image/v2/imageimport/testing/requests_test.go b/openstack/image/v2/imageimport/testing/requests_test.go index 05bcc9cafd..b46055953f 100644 --- a/openstack/image/v2/imageimport/testing/requests_test.go +++ b/openstack/image/v2/imageimport/testing/requests_test.go @@ -33,8 +33,8 @@ func TestGet(t *testing.T) { s, err := imageimport.Get(context.TODO(), client.ServiceClient(fakeServer)).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, s.ImportMethods.Description, "Import methods available.") - th.AssertEquals(t, s.ImportMethods.Type, "array") + th.AssertEquals(t, "Import methods available.", s.ImportMethods.Description) + th.AssertEquals(t, "array", s.ImportMethods.Type) th.AssertDeepEquals(t, s.ImportMethods.Value, validImportMethods) } diff --git a/openstack/image/v2/tasks/testing/requests_test.go b/openstack/image/v2/tasks/testing/requests_test.go index 1949d07c3a..3656919982 100644 --- a/openstack/image/v2/tasks/testing/requests_test.go +++ b/openstack/image/v2/tasks/testing/requests_test.go @@ -73,21 +73,21 @@ func TestGet(t *testing.T) { th.AssertEquals(t, s.Status, string(tasks.TaskStatusPending)) th.AssertEquals(t, s.CreatedAt, time.Date(2018, 7, 25, 8, 59, 13, 0, time.UTC)) th.AssertEquals(t, s.UpdatedAt, time.Date(2018, 7, 25, 8, 59, 14, 0, time.UTC)) - th.AssertEquals(t, s.Self, "/v2/tasks/1252f636-1246-4319-bfba-c47cde0efbe0") - th.AssertEquals(t, s.Owner, "424e7cf0243c468ca61732ba45973b3e") - th.AssertEquals(t, s.Message, "") - th.AssertEquals(t, s.Type, "import") - th.AssertEquals(t, s.ID, "1252f636-1246-4319-bfba-c47cde0efbe0") - th.AssertEquals(t, s.Schema, "/v2/schemas/task") + th.AssertEquals(t, "/v2/tasks/1252f636-1246-4319-bfba-c47cde0efbe0", s.Self) + th.AssertEquals(t, "424e7cf0243c468ca61732ba45973b3e", s.Owner) + th.AssertEquals(t, "", s.Message) + th.AssertEquals(t, "import", s.Type) + th.AssertEquals(t, "1252f636-1246-4319-bfba-c47cde0efbe0", s.ID) + th.AssertEquals(t, "/v2/schemas/task", s.Schema) th.AssertDeepEquals(t, s.Result, map[string]any(nil)) - th.AssertDeepEquals(t, s.Input, map[string]any{ + th.AssertDeepEquals(t, map[string]any{ "import_from": "http://download.cirros-cloud.net/0.4.0/cirros-0.4.0-x86_64-disk.img", "import_from_format": "raw", "image_properties": map[string]any{ "container_format": "bare", "disk_format": "raw", }, - }) + }, s.Input) } func TestCreate(t *testing.T) { @@ -122,19 +122,19 @@ func TestCreate(t *testing.T) { th.AssertEquals(t, s.Status, string(tasks.TaskStatusPending)) th.AssertEquals(t, s.CreatedAt, time.Date(2018, 7, 25, 11, 7, 54, 0, time.UTC)) th.AssertEquals(t, s.UpdatedAt, time.Date(2018, 7, 25, 11, 7, 54, 0, time.UTC)) - th.AssertEquals(t, s.Self, "/v2/tasks/d550c87d-86ed-430a-9895-c7a1f5ce87e9") - th.AssertEquals(t, s.Owner, "fb57277ef2f84a0e85b9018ec2dedbf7") - th.AssertEquals(t, s.Message, "") - th.AssertEquals(t, s.Type, "import") - th.AssertEquals(t, s.ID, "d550c87d-86ed-430a-9895-c7a1f5ce87e9") - th.AssertEquals(t, s.Schema, "/v2/schemas/task") + th.AssertEquals(t, "/v2/tasks/d550c87d-86ed-430a-9895-c7a1f5ce87e9", s.Self) + th.AssertEquals(t, "fb57277ef2f84a0e85b9018ec2dedbf7", s.Owner) + th.AssertEquals(t, "", s.Message) + th.AssertEquals(t, "import", s.Type) + th.AssertEquals(t, "d550c87d-86ed-430a-9895-c7a1f5ce87e9", s.ID) + th.AssertEquals(t, "/v2/schemas/task", s.Schema) th.AssertDeepEquals(t, s.Result, map[string]any(nil)) - th.AssertDeepEquals(t, s.Input, map[string]any{ + th.AssertDeepEquals(t, map[string]any{ "import_from": "https://cloud-images.ubuntu.com/bionic/current/bionic-server-cloudimg-amd64.img", "import_from_format": "raw", "image_properties": map[string]any{ "container_format": "bare", "disk_format": "raw", }, - }) + }, s.Input) } diff --git a/openstack/keymanager/v1/containers/testing/requests_test.go b/openstack/keymanager/v1/containers/testing/requests_test.go index 83fd23502c..3fb490c876 100644 --- a/openstack/keymanager/v1/containers/testing/requests_test.go +++ b/openstack/keymanager/v1/containers/testing/requests_test.go @@ -27,7 +27,7 @@ func TestListContainers(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.AssertEquals(t, count, 1) + th.AssertEquals(t, 1, count) } func TestListContainersAllPages(t *testing.T) { @@ -99,7 +99,7 @@ func TestListConsumers(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.AssertEquals(t, count, 1) + th.AssertEquals(t, 1, count) } func TestListConsumersAllPages(t *testing.T) { diff --git a/openstack/keymanager/v1/orders/testing/requests_test.go b/openstack/keymanager/v1/orders/testing/requests_test.go index f3545313df..1267cd3283 100644 --- a/openstack/keymanager/v1/orders/testing/requests_test.go +++ b/openstack/keymanager/v1/orders/testing/requests_test.go @@ -27,7 +27,7 @@ func TestListOrders(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.AssertEquals(t, count, 1) + th.AssertEquals(t, 1, count) } func TestListOrdersAllPages(t *testing.T) { diff --git a/openstack/keymanager/v1/secrets/testing/requests_test.go b/openstack/keymanager/v1/secrets/testing/requests_test.go index 92475da63f..5c6e408396 100644 --- a/openstack/keymanager/v1/secrets/testing/requests_test.go +++ b/openstack/keymanager/v1/secrets/testing/requests_test.go @@ -28,7 +28,7 @@ func TestListSecrets(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.AssertEquals(t, count, 1) + th.AssertEquals(t, 1, count) } func TestListSecretsAllPages(t *testing.T) { diff --git a/openstack/loadbalancer/v2/loadbalancers/testing/requests_test.go b/openstack/loadbalancer/v2/loadbalancers/testing/requests_test.go index 64a3ddc83f..b5a2a3bafe 100644 --- a/openstack/loadbalancer/v2/loadbalancers/testing/requests_test.go +++ b/openstack/loadbalancer/v2/loadbalancers/testing/requests_test.go @@ -211,7 +211,7 @@ func TestCascadingDeleteLoadbalancer(t *testing.T) { query, err := deleteOpts.ToLoadBalancerDeleteQuery() th.AssertNoErr(t, err) - th.AssertEquals(t, query, "?cascade=true") + th.AssertEquals(t, "?cascade=true", query) err = loadbalancers.Delete(context.TODO(), sc, "36e08a3e-a78f-4b40-a229-1e7e23eee1ab", deleteOpts).ExtractErr() th.AssertNoErr(t, err) diff --git a/openstack/messaging/v2/queues/testing/requests_test.go b/openstack/messaging/v2/queues/testing/requests_test.go index d64c374561..839f5ec122 100644 --- a/openstack/messaging/v2/queues/testing/requests_test.go +++ b/openstack/messaging/v2/queues/testing/requests_test.go @@ -27,7 +27,7 @@ func TestList(t *testing.T) { countField, err := page.(queues.QueuePage).GetCount() th.AssertNoErr(t, err) - th.AssertEquals(t, countField, 2) + th.AssertEquals(t, 2, countField) th.CheckDeepEquals(t, ExpectedQueueSlice[count], actual) count++ diff --git a/openstack/networking/v2/extensions/agents/testing/requests_test.go b/openstack/networking/v2/extensions/agents/testing/requests_test.go index a48d629eb5..9777578e33 100644 --- a/openstack/networking/v2/extensions/agents/testing/requests_test.go +++ b/openstack/networking/v2/extensions/agents/testing/requests_test.go @@ -72,24 +72,24 @@ func TestGet(t *testing.T) { s, err := agents.Get(context.TODO(), fake.ServiceClient(fakeServer), "43583cf5-472e-4dc8-af5b-6aed4c94ee3a").Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, s.ID, "43583cf5-472e-4dc8-af5b-6aed4c94ee3a") - th.AssertEquals(t, s.Binary, "neutron-openvswitch-agent") - th.AssertEquals(t, s.AdminStateUp, true) - th.AssertEquals(t, s.Alive, true) - th.AssertEquals(t, s.Topic, "N/A") - th.AssertEquals(t, s.Host, "compute3") - th.AssertEquals(t, s.AgentType, "Open vSwitch agent") + th.AssertEquals(t, "43583cf5-472e-4dc8-af5b-6aed4c94ee3a", s.ID) + th.AssertEquals(t, "neutron-openvswitch-agent", s.Binary) + th.AssertEquals(t, true, s.AdminStateUp) + th.AssertEquals(t, true, s.Alive) + th.AssertEquals(t, "N/A", s.Topic) + th.AssertEquals(t, "compute3", s.Host) + th.AssertEquals(t, "Open vSwitch agent", s.AgentType) th.AssertEquals(t, s.HeartbeatTimestamp, time.Date(2019, 1, 9, 11, 43, 01, 0, time.UTC)) th.AssertEquals(t, s.StartedAt, time.Date(2018, 6, 26, 21, 46, 20, 0, time.UTC)) th.AssertEquals(t, s.CreatedAt, time.Date(2017, 7, 26, 23, 2, 5, 0, time.UTC)) - th.AssertDeepEquals(t, s.Configurations, map[string]any{ + th.AssertDeepEquals(t, map[string]any{ "ovs_hybrid_plug": false, "datapath_type": "system", "vhostuser_socket_dir": "/var/run/openvswitch", "log_agent_heartbeats": false, "l2_population": true, "enable_distributed_routing": false, - }) + }, s.Configurations) } func TestUpdate(t *testing.T) { @@ -156,17 +156,17 @@ func TestListDHCPNetworks(t *testing.T) { th.AssertNoErr(t, err) var nilSlice []string - th.AssertEquals(t, len(s), 1) - th.AssertEquals(t, s[0].ID, "d32019d3-bc6e-4319-9c1d-6722fc136a22") - th.AssertEquals(t, s[0].AdminStateUp, true) - th.AssertEquals(t, s[0].ProjectID, "4fd44f30292945e481c7b8a0c8908869") - th.AssertEquals(t, s[0].Shared, false) - th.AssertEquals(t, s[0].Name, "net1") - th.AssertEquals(t, s[0].Status, "ACTIVE") + th.AssertEquals(t, 1, len(s)) + th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", s[0].ID) + th.AssertEquals(t, true, s[0].AdminStateUp) + th.AssertEquals(t, "4fd44f30292945e481c7b8a0c8908869", s[0].ProjectID) + th.AssertEquals(t, false, s[0].Shared) + th.AssertEquals(t, "net1", s[0].Name) + th.AssertEquals(t, "ACTIVE", s[0].Status) th.AssertDeepEquals(t, s[0].Tags, nilSlice) - th.AssertEquals(t, s[0].TenantID, "4fd44f30292945e481c7b8a0c8908869") - th.AssertDeepEquals(t, s[0].AvailabilityZoneHints, []string{}) - th.AssertDeepEquals(t, s[0].Subnets, []string{"54d6f61d-db07-451c-9ab3-b9609b6b6f0b"}) + th.AssertEquals(t, "4fd44f30292945e481c7b8a0c8908869", s[0].TenantID) + th.AssertDeepEquals(t, []string{}, s[0].AvailabilityZoneHints) + th.AssertDeepEquals(t, []string{"54d6f61d-db07-451c-9ab3-b9609b6b6f0b"}, s[0].Subnets) } @@ -234,11 +234,11 @@ func TestListBGPSpeakers(t *testing.T) { actual, err := agents.ExtractBGPSpeakers(page) th.AssertNoErr(t, err) - th.AssertEquals(t, len(actual), 1) - th.AssertEquals(t, actual[0].ID, "cab00464-284d-4251-9798-2b27db7b1668") - th.AssertEquals(t, actual[0].Name, "gophercloud-testing-speaker") - th.AssertEquals(t, actual[0].LocalAS, 12345) - th.AssertEquals(t, actual[0].IPVersion, 4) + th.AssertEquals(t, 1, len(actual)) + th.AssertEquals(t, "cab00464-284d-4251-9798-2b27db7b1668", actual[0].ID) + th.AssertEquals(t, "gophercloud-testing-speaker", actual[0].Name) + th.AssertEquals(t, 12345, actual[0].LocalAS) + th.AssertEquals(t, 4, actual[0].IPVersion) return true, nil }) th.AssertNoErr(t, err) @@ -373,19 +373,19 @@ func TestListL3Routers(t *testing.T) { } var nilSlice []string - th.AssertEquals(t, len(s), 2) - th.AssertEquals(t, s[0].ID, "915a14a6-867b-4af7-83d1-70efceb146f9") - th.AssertEquals(t, s[0].AdminStateUp, true) - th.AssertEquals(t, s[0].ProjectID, "0bd18306d801447bb457a46252d82d13") - th.AssertEquals(t, s[0].Name, "router2") - th.AssertEquals(t, s[0].Status, "ACTIVE") - th.AssertEquals(t, s[0].TenantID, "0bd18306d801447bb457a46252d82d13") - th.AssertDeepEquals(t, s[0].AvailabilityZoneHints, []string{}) + th.AssertEquals(t, 2, len(s)) + th.AssertEquals(t, "915a14a6-867b-4af7-83d1-70efceb146f9", s[0].ID) + th.AssertEquals(t, true, s[0].AdminStateUp) + th.AssertEquals(t, "0bd18306d801447bb457a46252d82d13", s[0].ProjectID) + th.AssertEquals(t, "router2", s[0].Name) + th.AssertEquals(t, "ACTIVE", s[0].Status) + th.AssertEquals(t, "0bd18306d801447bb457a46252d82d13", s[0].TenantID) + th.AssertDeepEquals(t, []string{}, s[0].AvailabilityZoneHints) th.AssertDeepEquals(t, s[0].Routes, routes) th.AssertDeepEquals(t, s[0].GatewayInfo, gw) th.AssertDeepEquals(t, s[0].Tags, nilSlice) - th.AssertEquals(t, s[1].ID, "f8a44de0-fc8e-45df-93c7-f79bf3b01c95") - th.AssertEquals(t, s[1].Name, "router1") + th.AssertEquals(t, "f8a44de0-fc8e-45df-93c7-f79bf3b01c95", s[1].ID) + th.AssertEquals(t, "router1", s[1].Name) } diff --git a/openstack/networking/v2/extensions/attributestags/testing/requests_test.go b/openstack/networking/v2/extensions/attributestags/testing/requests_test.go index dc35bd12dc..dfeab5abd5 100644 --- a/openstack/networking/v2/extensions/attributestags/testing/requests_test.go +++ b/openstack/networking/v2/extensions/attributestags/testing/requests_test.go @@ -34,7 +34,7 @@ func TestReplaceAll(t *testing.T) { res, err := attributestags.ReplaceAll(context.TODO(), fake.ServiceClient(fakeServer), "networks", "fakeid", opts).Extract() th.AssertNoErr(t, err) - th.AssertDeepEquals(t, res, []string{"abc", "xyz"}) + th.AssertDeepEquals(t, []string{"abc", "xyz"}, res) } func TestList(t *testing.T) { @@ -54,7 +54,7 @@ func TestList(t *testing.T) { res, err := attributestags.List(context.TODO(), fake.ServiceClient(fakeServer), "networks", "fakeid").Extract() th.AssertNoErr(t, err) - th.AssertDeepEquals(t, res, []string{"abc", "xyz"}) + th.AssertDeepEquals(t, []string{"abc", "xyz"}, res) } func TestDeleteAll(t *testing.T) { diff --git a/openstack/networking/v2/extensions/bgp/speakers/testing/requests_test.go b/openstack/networking/v2/extensions/bgp/speakers/testing/requests_test.go index 99259982c8..74dd875410 100644 --- a/openstack/networking/v2/extensions/bgp/speakers/testing/requests_test.go +++ b/openstack/networking/v2/extensions/bgp/speakers/testing/requests_test.go @@ -88,8 +88,8 @@ func TestCreate(t *testing.T) { r, err := speakers.Create(context.TODO(), fake.ServiceClient(fakeServer), opts).Extract() th.AssertNoErr(t, err) th.AssertEquals(t, r.Name, opts.Name) - th.AssertEquals(t, r.LocalAS, 2000) - th.AssertEquals(t, len(r.Networks), 0) + th.AssertEquals(t, 2000, r.LocalAS) + th.AssertEquals(t, 0, len(r.Networks)) th.AssertEquals(t, r.IPVersion, opts.IPVersion) th.AssertEquals(t, r.AdvertiseFloatingIPHostRoutes, *opts.AdvertiseFloatingIPHostRoutes) th.AssertEquals(t, r.AdvertiseTenantNetworks, *opts.AdvertiseTenantNetworks) @@ -230,7 +230,7 @@ func TestGetAdvertisedRoutes(t *testing.T) { {NextHop: "172.17.128.218", Destination: "172.17.129.0/27"}, {NextHop: "172.17.128.231", Destination: "172.17.129.160/27"}, } - th.CheckDeepEquals(t, count, 1) + th.CheckDeepEquals(t, 1, count) th.CheckDeepEquals(t, expected, actual) return true, nil }) diff --git a/openstack/networking/v2/extensions/dns/testing/fixtures_test.go b/openstack/networking/v2/extensions/dns/testing/fixtures_test.go index f09a1033c6..3af9bac7eb 100644 --- a/openstack/networking/v2/extensions/dns/testing/fixtures_test.go +++ b/openstack/networking/v2/extensions/dns/testing/fixtures_test.go @@ -73,7 +73,7 @@ func PortHandleListSuccessfully(t *testing.T, fakeServer th.FakeServer) { th.TestMethod(t, r, "GET") th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) - th.AssertEquals(t, r.RequestURI, "/v2.0/ports?dns_name=test-port") + th.AssertEquals(t, "/v2.0/ports?dns_name=test-port", r.RequestURI) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) @@ -224,7 +224,7 @@ func FloatingIPHandleList(t *testing.T, fakeServer th.FakeServer) { th.TestMethod(t, r, "GET") th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) - th.AssertEquals(t, r.RequestURI, "/v2.0/floatingips?dns_domain=local.&dns_name=test-fip") + th.AssertEquals(t, "/v2.0/floatingips?dns_domain=local.&dns_name=test-fip", r.RequestURI) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) @@ -273,7 +273,7 @@ func NetworkHandleList(t *testing.T, fakeServer th.FakeServer) { th.TestMethod(t, r, "GET") th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) - th.AssertEquals(t, r.RequestURI, "/v2.0/networks?dns_domain=local.") + th.AssertEquals(t, "/v2.0/networks?dns_domain=local.", r.RequestURI) w.Header().Add("Content-Type", "application/json") w.WriteHeader(http.StatusOK) diff --git a/openstack/networking/v2/extensions/dns/testing/requests_test.go b/openstack/networking/v2/extensions/dns/testing/requests_test.go index 886be44891..e713bb7b63 100644 --- a/openstack/networking/v2/extensions/dns/testing/requests_test.go +++ b/openstack/networking/v2/extensions/dns/testing/requests_test.go @@ -99,28 +99,28 @@ func TestPortGet(t *testing.T) { err := ports.Get(context.TODO(), fake.ServiceClient(fakeServer), "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2").ExtractInto(&s) th.AssertNoErr(t, err) - th.AssertEquals(t, s.Status, "ACTIVE") - th.AssertEquals(t, s.Name, "") - th.AssertEquals(t, s.AdminStateUp, true) - th.AssertEquals(t, s.NetworkID, "a87cc70a-3e15-4acf-8205-9b711a3531b7") - th.AssertEquals(t, s.TenantID, "7e02058126cc4950b75f9970368ba177") - th.AssertEquals(t, s.DeviceOwner, "network:router_interface") - th.AssertEquals(t, s.MACAddress, "fa:16:3e:23:fd:d7") - th.AssertDeepEquals(t, s.FixedIPs, []ports.IP{ + th.AssertEquals(t, "ACTIVE", s.Status) + th.AssertEquals(t, "", s.Name) + th.AssertEquals(t, true, s.AdminStateUp) + th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", s.NetworkID) + th.AssertEquals(t, "7e02058126cc4950b75f9970368ba177", s.TenantID) + th.AssertEquals(t, "network:router_interface", s.DeviceOwner) + th.AssertEquals(t, "fa:16:3e:23:fd:d7", s.MACAddress) + th.AssertDeepEquals(t, []ports.IP{ {SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.1"}, - }) - th.AssertEquals(t, s.ID, "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2") - th.AssertDeepEquals(t, s.SecurityGroups, []string{}) - th.AssertEquals(t, s.DeviceID, "5e3898d7-11be-483e-9732-b2f5eccd2b2e") + }, s.FixedIPs) + th.AssertEquals(t, "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2", s.ID) + th.AssertDeepEquals(t, []string{}, s.SecurityGroups) + th.AssertEquals(t, "5e3898d7-11be-483e-9732-b2f5eccd2b2e", s.DeviceID) - th.AssertEquals(t, s.DNSName, "test-port") - th.AssertDeepEquals(t, s.DNSAssignment, []map[string]string{ + th.AssertEquals(t, "test-port", s.DNSName) + th.AssertDeepEquals(t, []map[string]string{ { "hostname": "test-port", "ip_address": "172.24.4.2", "fqdn": "test-port.openstack.local.", }, - }) + }, s.DNSAssignment) } func TestPortCreate(t *testing.T) { @@ -150,27 +150,27 @@ func TestPortCreate(t *testing.T) { err := ports.Create(context.TODO(), fake.ServiceClient(fakeServer), createOpts).ExtractInto(&s) th.AssertNoErr(t, err) - th.AssertEquals(t, s.Status, "DOWN") - th.AssertEquals(t, s.Name, "private-port") - th.AssertEquals(t, s.AdminStateUp, true) - th.AssertEquals(t, s.NetworkID, "a87cc70a-3e15-4acf-8205-9b711a3531b7") - th.AssertEquals(t, s.TenantID, "d6700c0c9ffa4f1cb322cd4a1f3906fa") - th.AssertEquals(t, s.DeviceOwner, "") - th.AssertEquals(t, s.MACAddress, "fa:16:3e:c9:cb:f0") - th.AssertDeepEquals(t, s.FixedIPs, []ports.IP{ + th.AssertEquals(t, "DOWN", s.Status) + th.AssertEquals(t, "private-port", s.Name) + th.AssertEquals(t, true, s.AdminStateUp) + th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", s.NetworkID) + th.AssertEquals(t, "d6700c0c9ffa4f1cb322cd4a1f3906fa", s.TenantID) + th.AssertEquals(t, "", s.DeviceOwner) + th.AssertEquals(t, "fa:16:3e:c9:cb:f0", s.MACAddress) + th.AssertDeepEquals(t, []ports.IP{ {SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.2"}, - }) - th.AssertEquals(t, s.ID, "65c0ee9f-d634-4522-8954-51021b570b0d") - th.AssertDeepEquals(t, s.SecurityGroups, []string{"f0ac4394-7e4a-4409-9701-ba8be283dbc3"}) + }, s.FixedIPs) + th.AssertEquals(t, "65c0ee9f-d634-4522-8954-51021b570b0d", s.ID) + th.AssertDeepEquals(t, []string{"f0ac4394-7e4a-4409-9701-ba8be283dbc3"}, s.SecurityGroups) - th.AssertEquals(t, s.DNSName, "test-port") - th.AssertDeepEquals(t, s.DNSAssignment, []map[string]string{ + th.AssertEquals(t, "test-port", s.DNSName) + th.AssertDeepEquals(t, []map[string]string{ { "hostname": "test-port", "ip_address": "172.24.4.2", "fqdn": "test-port.openstack.local.", }, - }) + }, s.DNSAssignment) } func TestPortRequiredCreateOpts(t *testing.T) { @@ -209,19 +209,19 @@ func TestPortUpdate(t *testing.T) { err := ports.Update(context.TODO(), fake.ServiceClient(fakeServer), "65c0ee9f-d634-4522-8954-51021b570b0d", updateOpts).ExtractInto(&s) th.AssertNoErr(t, err) - th.AssertEquals(t, s.Name, "new_port_name") - th.AssertDeepEquals(t, s.FixedIPs, []ports.IP{ + th.AssertEquals(t, "new_port_name", s.Name) + th.AssertDeepEquals(t, []ports.IP{ {SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.3"}, - }) - th.AssertDeepEquals(t, s.SecurityGroups, []string{"f0ac4394-7e4a-4409-9701-ba8be283dbc3"}) - th.AssertEquals(t, s.DNSName, "test-port1") - th.AssertDeepEquals(t, s.DNSAssignment, []map[string]string{ + }, s.FixedIPs) + th.AssertDeepEquals(t, []string{"f0ac4394-7e4a-4409-9701-ba8be283dbc3"}, s.SecurityGroups) + th.AssertEquals(t, "test-port1", s.DNSName) + th.AssertDeepEquals(t, []map[string]string{ { "hostname": "test-port1", "ip_address": "172.24.4.2", "fqdn": "test-port1.openstack.local.", }, - }) + }, s.DNSAssignment) } func TestFloatingIPGet(t *testing.T) { diff --git a/openstack/networking/v2/extensions/fwaas_v2/groups/testing/requests_test.go b/openstack/networking/v2/extensions/fwaas_v2/groups/testing/requests_test.go index 2e903b6477..54c5c6c230 100644 --- a/openstack/networking/v2/extensions/fwaas_v2/groups/testing/requests_test.go +++ b/openstack/networking/v2/extensions/fwaas_v2/groups/testing/requests_test.go @@ -343,8 +343,8 @@ func TestRemoveIngressPolicy(t *testing.T) { removeIngressPolicy, err := groups.RemoveIngressPolicy(context.TODO(), fake.ServiceClient(fakeServer), "6bfb0f10-07f7-4a40-b534-bad4b4ca3428").Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, removeIngressPolicy.IngressFirewallPolicyID, "") - th.AssertEquals(t, removeIngressPolicy.EgressFirewallPolicyID, "43a11f3a-ddac-4129-9469-02b9df26548e") + th.AssertEquals(t, "", removeIngressPolicy.IngressFirewallPolicyID) + th.AssertEquals(t, "43a11f3a-ddac-4129-9469-02b9df26548e", removeIngressPolicy.EgressFirewallPolicyID) } func TestRemoveEgressPolicy(t *testing.T) { @@ -391,8 +391,8 @@ func TestRemoveEgressPolicy(t *testing.T) { removeEgressPolicy, err := groups.RemoveEgressPolicy(context.TODO(), fake.ServiceClient(fakeServer), "6bfb0f10-07f7-4a40-b534-bad4b4ca3428").Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, removeEgressPolicy.IngressFirewallPolicyID, "e3f11142-3792-454b-8d3e-91ac1bf127b4") - th.AssertEquals(t, removeEgressPolicy.EgressFirewallPolicyID, "") + th.AssertEquals(t, "e3f11142-3792-454b-8d3e-91ac1bf127b4", removeEgressPolicy.IngressFirewallPolicyID) + th.AssertEquals(t, "", removeEgressPolicy.EgressFirewallPolicyID) } func TestDelete(t *testing.T) { diff --git a/openstack/networking/v2/extensions/layer3/addressscopes/testing/requests_test.go b/openstack/networking/v2/extensions/layer3/addressscopes/testing/requests_test.go index 10738657bb..2e1e8eaf46 100644 --- a/openstack/networking/v2/extensions/layer3/addressscopes/testing/requests_test.go +++ b/openstack/networking/v2/extensions/layer3/addressscopes/testing/requests_test.go @@ -69,12 +69,12 @@ func TestGet(t *testing.T) { s, err := addressscopes.Get(context.TODO(), fake.ServiceClient(fakeServer), "9cc35860-522a-4d35-974d-51d4b011801e").Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, s.ID, "9cc35860-522a-4d35-974d-51d4b011801e") - th.AssertEquals(t, s.Name, "scopev4") - th.AssertEquals(t, s.TenantID, "4a9807b773404e979b19633f38370643") - th.AssertEquals(t, s.ProjectID, "4a9807b773404e979b19633f38370643") - th.AssertEquals(t, s.IPVersion, 4) - th.AssertEquals(t, s.Shared, false) + th.AssertEquals(t, "9cc35860-522a-4d35-974d-51d4b011801e", s.ID) + th.AssertEquals(t, "scopev4", s.Name) + th.AssertEquals(t, "4a9807b773404e979b19633f38370643", s.TenantID) + th.AssertEquals(t, "4a9807b773404e979b19633f38370643", s.ProjectID) + th.AssertEquals(t, 4, s.IPVersion) + th.AssertEquals(t, false, s.Shared) } func TestCreate(t *testing.T) { @@ -102,12 +102,12 @@ func TestCreate(t *testing.T) { s, err := addressscopes.Create(context.TODO(), fake.ServiceClient(fakeServer), opts).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, s.Name, "test0") - th.AssertEquals(t, s.Shared, true) - th.AssertEquals(t, s.IPVersion, 4) - th.AssertEquals(t, s.TenantID, "4a9807b773404e979b19633f38370643") - th.AssertEquals(t, s.ProjectID, "4a9807b773404e979b19633f38370643") - th.AssertEquals(t, s.ID, "9cc35860-522a-4d35-974d-51d4b011801e") + th.AssertEquals(t, "test0", s.Name) + th.AssertEquals(t, true, s.Shared) + th.AssertEquals(t, 4, s.IPVersion) + th.AssertEquals(t, "4a9807b773404e979b19633f38370643", s.TenantID) + th.AssertEquals(t, "4a9807b773404e979b19633f38370643", s.ProjectID) + th.AssertEquals(t, "9cc35860-522a-4d35-974d-51d4b011801e", s.ID) } func TestUpdate(t *testing.T) { @@ -136,8 +136,8 @@ func TestUpdate(t *testing.T) { s, err := addressscopes.Update(context.TODO(), fake.ServiceClient(fakeServer), "9cc35860-522a-4d35-974d-51d4b011801e", updateOpts).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, s.Name, "test1") - th.AssertEquals(t, s.Shared, true) + th.AssertEquals(t, "test1", s.Name) + th.AssertEquals(t, true, s.Shared) } func TestDelete(t *testing.T) { diff --git a/openstack/networking/v2/extensions/layer3/extraroutes/testing/requests_test.go b/openstack/networking/v2/extensions/layer3/extraroutes/testing/requests_test.go index ec1676290d..c9aa0864a4 100644 --- a/openstack/networking/v2/extensions/layer3/extraroutes/testing/requests_test.go +++ b/openstack/networking/v2/extensions/layer3/extraroutes/testing/requests_test.go @@ -66,7 +66,7 @@ func TestAddExtraRoutes(t *testing.T) { n, err := extraroutes.Add(context.TODO(), fake.ServiceClient(fakeServer), "4e8e5957-649f-477b-9e5b-f1f75b21c03c", options).Extract() th.AssertNoErr(t, err) - th.AssertDeepEquals(t, n.Routes, []routers.Route{ + th.AssertDeepEquals(t, []routers.Route{ { DestinationCIDR: "10.0.1.0/24", NextHop: "10.0.0.11", @@ -83,7 +83,7 @@ func TestAddExtraRoutes(t *testing.T) { DestinationCIDR: "10.0.4.0/24", NextHop: "10.0.0.14", }, - }) + }, n.Routes) } func TestRemoveExtraRoutes(t *testing.T) { @@ -138,7 +138,7 @@ func TestRemoveExtraRoutes(t *testing.T) { n, err := extraroutes.Remove(context.TODO(), fake.ServiceClient(fakeServer), "4e8e5957-649f-477b-9e5b-f1f75b21c03c", options).Extract() th.AssertNoErr(t, err) - th.AssertDeepEquals(t, n.Routes, []routers.Route{ + th.AssertDeepEquals(t, []routers.Route{ { DestinationCIDR: "10.0.1.0/24", NextHop: "10.0.0.11", @@ -147,5 +147,5 @@ func TestRemoveExtraRoutes(t *testing.T) { DestinationCIDR: "10.0.2.0/24", NextHop: "10.0.0.12", }, - }) + }, n.Routes) } diff --git a/openstack/networking/v2/extensions/layer3/routers/testing/requests_test.go b/openstack/networking/v2/extensions/layer3/routers/testing/requests_test.go index 1125aa12c4..9404e24d02 100644 --- a/openstack/networking/v2/extensions/layer3/routers/testing/requests_test.go +++ b/openstack/networking/v2/extensions/layer3/routers/testing/requests_test.go @@ -263,20 +263,20 @@ func TestGet(t *testing.T) { n, err := routers.Get(context.TODO(), fake.ServiceClient(fakeServer), "a07eea83-7710-4860-931b-5fe220fae533").Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.Status, "ACTIVE") - th.AssertDeepEquals(t, n.GatewayInfo, routers.GatewayInfo{ + th.AssertEquals(t, "ACTIVE", n.Status) + th.AssertDeepEquals(t, routers.GatewayInfo{ NetworkID: "85d76829-6415-48ff-9c63-5c5ca8c61ac6", ExternalFixedIPs: []routers.ExternalFixedIP{ {IPAddress: "198.51.100.33", SubnetID: "1d699529-bdfd-43f8-bcaa-bff00c547af2"}, }, QoSPolicyID: "6601bae5-f15a-4687-8be9-ddec9a2f8a8b", - }) - th.AssertEquals(t, n.Name, "router1") - th.AssertEquals(t, n.AdminStateUp, true) - th.AssertEquals(t, n.TenantID, "d6554fe62e2f41efbb6e026fad5c1542") - th.AssertEquals(t, n.ID, "a07eea83-7710-4860-931b-5fe220fae533") - th.AssertDeepEquals(t, n.Routes, []routers.Route{{DestinationCIDR: "40.0.1.0/24", NextHop: "10.1.0.10"}}) - th.AssertDeepEquals(t, n.AvailabilityZoneHints, []string{"zone1", "zone2"}) + }, n.GatewayInfo) + th.AssertEquals(t, "router1", n.Name) + th.AssertEquals(t, true, n.AdminStateUp) + th.AssertEquals(t, "d6554fe62e2f41efbb6e026fad5c1542", n.TenantID) + th.AssertEquals(t, "a07eea83-7710-4860-931b-5fe220fae533", n.ID) + th.AssertDeepEquals(t, []routers.Route{{DestinationCIDR: "40.0.1.0/24", NextHop: "10.1.0.10"}}, n.Routes) + th.AssertDeepEquals(t, []string{"zone1", "zone2"}, n.AvailabilityZoneHints) } func TestUpdate(t *testing.T) { @@ -350,9 +350,9 @@ func TestUpdate(t *testing.T) { {IPAddress: "192.0.2.17", SubnetID: "ab561bc4-1a8e-48f2-9fbd-376fcb1a1def"}, } - th.AssertEquals(t, n.Name, "new_name") + th.AssertEquals(t, "new_name", n.Name) th.AssertDeepEquals(t, n.GatewayInfo, gwi) - th.AssertDeepEquals(t, n.Routes, []routers.Route{{DestinationCIDR: "40.0.1.0/24", NextHop: "10.1.0.10"}}) + th.AssertDeepEquals(t, []routers.Route{{DestinationCIDR: "40.0.1.0/24", NextHop: "10.1.0.10"}}, n.Routes) } func TestUpdateWithoutRoutes(t *testing.T) { @@ -406,8 +406,8 @@ func TestUpdateWithoutRoutes(t *testing.T) { n, err := routers.Update(context.TODO(), fake.ServiceClient(fakeServer), "4e8e5957-649f-477b-9e5b-f1f75b21c03c", options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.Name, "new_name") - th.AssertDeepEquals(t, n.Routes, []routers.Route{{DestinationCIDR: "40.0.1.0/24", NextHop: "10.1.0.10"}}) + th.AssertEquals(t, "new_name", n.Name) + th.AssertDeepEquals(t, []routers.Route{{DestinationCIDR: "40.0.1.0/24", NextHop: "10.1.0.10"}}, n.Routes) } func TestAllRoutesRemoved(t *testing.T) { @@ -454,7 +454,7 @@ func TestAllRoutesRemoved(t *testing.T) { n, err := routers.Update(context.TODO(), fake.ServiceClient(fakeServer), "4e8e5957-649f-477b-9e5b-f1f75b21c03c", options).Extract() th.AssertNoErr(t, err) - th.AssertDeepEquals(t, n.Routes, []routers.Route{}) + th.AssertDeepEquals(t, []routers.Route{}, n.Routes) } func TestDelete(t *testing.T) { @@ -760,9 +760,9 @@ func TestAddExternalGateways(t *testing.T) { n, err := routers.AddExternalGateways(context.TODO(), fake.ServiceClient(fakeServer), "4e8e5957-649f-477b-9e5b-f1f75b21c03c", opts).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.Name, "router1") - th.AssertEquals(t, n.ID, "4e8e5957-649f-477b-9e5b-f1f75b21c03c") - th.AssertEquals(t, n.GatewayInfo.NetworkID, "8ca37218-28ff-41cb-9b10-039601ea7e6b") + th.AssertEquals(t, "router1", n.Name) + th.AssertEquals(t, "4e8e5957-649f-477b-9e5b-f1f75b21c03c", n.ID) + th.AssertEquals(t, "8ca37218-28ff-41cb-9b10-039601ea7e6b", n.GatewayInfo.NetworkID) } func TestUpdateExternalGateways(t *testing.T) { @@ -831,9 +831,9 @@ func TestUpdateExternalGateways(t *testing.T) { n, err := routers.UpdateExternalGateways(context.TODO(), fake.ServiceClient(fakeServer), "4e8e5957-649f-477b-9e5b-f1f75b21c03c", opts).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.Name, "router1") - th.AssertEquals(t, n.ID, "4e8e5957-649f-477b-9e5b-f1f75b21c03c") - th.AssertEquals(t, *n.GatewayInfo.EnableSNAT, true) + th.AssertEquals(t, "router1", n.Name) + th.AssertEquals(t, "4e8e5957-649f-477b-9e5b-f1f75b21c03c", n.ID) + th.AssertEquals(t, true, *n.GatewayInfo.EnableSNAT) } func TestRemoveExternalGateways(t *testing.T) { @@ -893,7 +893,7 @@ func TestRemoveExternalGateways(t *testing.T) { n, err := routers.RemoveExternalGateways(context.TODO(), fake.ServiceClient(fakeServer), "4e8e5957-649f-477b-9e5b-f1f75b21c03c", opts).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.Name, "router1") - th.AssertEquals(t, n.ID, "4e8e5957-649f-477b-9e5b-f1f75b21c03c") - th.AssertEquals(t, n.GatewayInfo.NetworkID, "") + th.AssertEquals(t, "router1", n.Name) + th.AssertEquals(t, "4e8e5957-649f-477b-9e5b-f1f75b21c03c", n.ID) + th.AssertEquals(t, "", n.GatewayInfo.NetworkID) } diff --git a/openstack/networking/v2/extensions/networkipavailabilities/testing/requests_test.go b/openstack/networking/v2/extensions/networkipavailabilities/testing/requests_test.go index 349d4784dd..cd1c55694b 100644 --- a/openstack/networking/v2/extensions/networkipavailabilities/testing/requests_test.go +++ b/openstack/networking/v2/extensions/networkipavailabilities/testing/requests_test.go @@ -71,13 +71,13 @@ func TestGet(t *testing.T) { s, err := networkipavailabilities.Get(context.TODO(), fake.ServiceClient(fakeServer), "cf11ab78-2302-49fa-870f-851a08c7afb8").Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, s.NetworkID, "cf11ab78-2302-49fa-870f-851a08c7afb8") - th.AssertEquals(t, s.NetworkName, "public") - th.AssertEquals(t, s.ProjectID, "424e7cf0243c468ca61732ba45973b3e") - th.AssertEquals(t, s.TenantID, "424e7cf0243c468ca61732ba45973b3e") - th.AssertEquals(t, s.TotalIPs, "253") - th.AssertEquals(t, s.UsedIPs, "3") - th.AssertDeepEquals(t, s.SubnetIPAvailabilities, []networkipavailabilities.SubnetIPAvailability{ + th.AssertEquals(t, "cf11ab78-2302-49fa-870f-851a08c7afb8", s.NetworkID) + th.AssertEquals(t, "public", s.NetworkName) + th.AssertEquals(t, "424e7cf0243c468ca61732ba45973b3e", s.ProjectID) + th.AssertEquals(t, "424e7cf0243c468ca61732ba45973b3e", s.TenantID) + th.AssertEquals(t, "253", s.TotalIPs) + th.AssertEquals(t, "3", s.UsedIPs) + th.AssertDeepEquals(t, []networkipavailabilities.SubnetIPAvailability{ { SubnetID: "4afe6e5f-9649-40db-b18f-64c7ead942bd", SubnetName: "public-subnet", @@ -86,5 +86,5 @@ func TestGet(t *testing.T) { TotalIPs: "253", UsedIPs: "3", }, - }) + }, s.SubnetIPAvailabilities) } diff --git a/openstack/networking/v2/extensions/portsbinding/testing/requests_test.go b/openstack/networking/v2/extensions/portsbinding/testing/requests_test.go index e48981fd06..e973afdf01 100644 --- a/openstack/networking/v2/extensions/portsbinding/testing/requests_test.go +++ b/openstack/networking/v2/extensions/portsbinding/testing/requests_test.go @@ -75,24 +75,24 @@ func TestGet(t *testing.T) { err := ports.Get(context.TODO(), fake.ServiceClient(fakeServer), "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2").ExtractInto(&s) th.AssertNoErr(t, err) - th.AssertEquals(t, s.Status, "ACTIVE") - th.AssertEquals(t, s.Name, "") - th.AssertEquals(t, s.AdminStateUp, true) - th.AssertEquals(t, s.NetworkID, "a87cc70a-3e15-4acf-8205-9b711a3531b7") - th.AssertEquals(t, s.TenantID, "7e02058126cc4950b75f9970368ba177") - th.AssertEquals(t, s.DeviceOwner, "network:router_interface") - th.AssertEquals(t, s.MACAddress, "fa:16:3e:23:fd:d7") - th.AssertDeepEquals(t, s.FixedIPs, []ports.IP{ + th.AssertEquals(t, "ACTIVE", s.Status) + th.AssertEquals(t, "", s.Name) + th.AssertEquals(t, true, s.AdminStateUp) + th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", s.NetworkID) + th.AssertEquals(t, "7e02058126cc4950b75f9970368ba177", s.TenantID) + th.AssertEquals(t, "network:router_interface", s.DeviceOwner) + th.AssertEquals(t, "fa:16:3e:23:fd:d7", s.MACAddress) + th.AssertDeepEquals(t, []ports.IP{ {SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.1"}, - }) - th.AssertEquals(t, s.ID, "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2") - th.AssertDeepEquals(t, s.SecurityGroups, []string{}) - th.AssertEquals(t, s.DeviceID, "5e3898d7-11be-483e-9732-b2f5eccd2b2e") - - th.AssertEquals(t, s.HostID, "devstack") - th.AssertEquals(t, s.VNICType, "normal") - th.AssertEquals(t, s.VIFType, "ovs") - th.AssertDeepEquals(t, s.VIFDetails, map[string]any{"port_filter": true, "ovs_hybrid_plug": true}) + }, s.FixedIPs) + th.AssertEquals(t, "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2", s.ID) + th.AssertDeepEquals(t, []string{}, s.SecurityGroups) + th.AssertEquals(t, "5e3898d7-11be-483e-9732-b2f5eccd2b2e", s.DeviceID) + + th.AssertEquals(t, "devstack", s.HostID) + th.AssertEquals(t, "normal", s.VNICType) + th.AssertEquals(t, "ovs", s.VIFType) + th.AssertDeepEquals(t, map[string]any{"port_filter": true, "ovs_hybrid_plug": true}, s.VIFDetails) } func TestCreate(t *testing.T) { @@ -126,20 +126,20 @@ func TestCreate(t *testing.T) { err := ports.Create(context.TODO(), fake.ServiceClient(fakeServer), createOpts).ExtractInto(&s) th.AssertNoErr(t, err) - th.AssertEquals(t, s.Status, "DOWN") - th.AssertEquals(t, s.Name, "private-port") - th.AssertEquals(t, s.AdminStateUp, true) - th.AssertEquals(t, s.NetworkID, "a87cc70a-3e15-4acf-8205-9b711a3531b7") - th.AssertEquals(t, s.TenantID, "d6700c0c9ffa4f1cb322cd4a1f3906fa") - th.AssertEquals(t, s.DeviceOwner, "") - th.AssertEquals(t, s.MACAddress, "fa:16:3e:c9:cb:f0") - th.AssertDeepEquals(t, s.FixedIPs, []ports.IP{ + th.AssertEquals(t, "DOWN", s.Status) + th.AssertEquals(t, "private-port", s.Name) + th.AssertEquals(t, true, s.AdminStateUp) + th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", s.NetworkID) + th.AssertEquals(t, "d6700c0c9ffa4f1cb322cd4a1f3906fa", s.TenantID) + th.AssertEquals(t, "", s.DeviceOwner) + th.AssertEquals(t, "fa:16:3e:c9:cb:f0", s.MACAddress) + th.AssertDeepEquals(t, []ports.IP{ {SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.2"}, - }) - th.AssertEquals(t, s.ID, "65c0ee9f-d634-4522-8954-51021b570b0d") - th.AssertDeepEquals(t, s.SecurityGroups, []string{"f0ac4394-7e4a-4409-9701-ba8be283dbc3"}) - th.AssertEquals(t, s.HostID, "HOST1") - th.AssertEquals(t, s.VNICType, "normal") + }, s.FixedIPs) + th.AssertEquals(t, "65c0ee9f-d634-4522-8954-51021b570b0d", s.ID) + th.AssertDeepEquals(t, []string{"f0ac4394-7e4a-4409-9701-ba8be283dbc3"}, s.SecurityGroups) + th.AssertEquals(t, "HOST1", s.HostID) + th.AssertEquals(t, "normal", s.VNICType) } func TestRequiredCreateOpts(t *testing.T) { @@ -182,11 +182,11 @@ func TestUpdate(t *testing.T) { err := ports.Update(context.TODO(), fake.ServiceClient(fakeServer), "65c0ee9f-d634-4522-8954-51021b570b0d", updateOpts).ExtractInto(&s) th.AssertNoErr(t, err) - th.AssertEquals(t, s.Name, "new_port_name") - th.AssertDeepEquals(t, s.FixedIPs, []ports.IP{ + th.AssertEquals(t, "new_port_name", s.Name) + th.AssertDeepEquals(t, []ports.IP{ {SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.3"}, - }) - th.AssertDeepEquals(t, s.SecurityGroups, []string{"f0ac4394-7e4a-4409-9701-ba8be283dbc3"}) - th.AssertEquals(t, s.HostID, "HOST1") - th.AssertEquals(t, s.VNICType, "normal") + }, s.FixedIPs) + th.AssertDeepEquals(t, []string{"f0ac4394-7e4a-4409-9701-ba8be283dbc3"}, s.SecurityGroups) + th.AssertEquals(t, "HOST1", s.HostID) + th.AssertEquals(t, "normal", s.VNICType) } diff --git a/openstack/networking/v2/extensions/portstrustedvif/testing/requests_test.go b/openstack/networking/v2/extensions/portstrustedvif/testing/requests_test.go index e768dda87b..47ecdc7db5 100644 --- a/openstack/networking/v2/extensions/portstrustedvif/testing/requests_test.go +++ b/openstack/networking/v2/extensions/portstrustedvif/testing/requests_test.go @@ -93,23 +93,23 @@ func TestGet(t *testing.T) { err := ports.Get(context.TODO(), fake.ServiceClient(fakeServer), "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2").ExtractInto(&s) th.AssertNoErr(t, err) - th.AssertEquals(t, s.Status, "DOWN") - th.AssertEquals(t, s.Name, "private-port") - th.AssertEquals(t, s.AdminStateUp, true) - th.AssertEquals(t, s.NetworkID, "a87cc70a-3e15-4acf-8205-9b711a3531b7") - th.AssertEquals(t, s.TenantID, "d6700c0c9ffa4f1cb322cd4a1f3906fa") - th.AssertEquals(t, s.DeviceOwner, "") - th.AssertEquals(t, s.MACAddress, "fa:16:3e:c9:cb:f0") - th.AssertDeepEquals(t, s.FixedIPs, []ports.IP{ + th.AssertEquals(t, "DOWN", s.Status) + th.AssertEquals(t, "private-port", s.Name) + th.AssertEquals(t, true, s.AdminStateUp) + th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", s.NetworkID) + th.AssertEquals(t, "d6700c0c9ffa4f1cb322cd4a1f3906fa", s.TenantID) + th.AssertEquals(t, "", s.DeviceOwner) + th.AssertEquals(t, "fa:16:3e:c9:cb:f0", s.MACAddress) + th.AssertDeepEquals(t, []ports.IP{ {SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.1"}, - }) - th.AssertEquals(t, s.ID, "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2") - th.AssertEquals(t, s.DeviceID, "") + }, s.FixedIPs) + th.AssertEquals(t, "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2", s.ID) + th.AssertEquals(t, "", s.DeviceID) if s.PortTrustedVIF == nil { t.Fatalf("Expected s.PortTrustedVIF to be not nil") } - th.AssertEquals(t, *s.PortTrustedVIF, false) + th.AssertEquals(t, false, *s.PortTrustedVIF) } func TestGetUnset(t *testing.T) { @@ -134,18 +134,18 @@ func TestGetUnset(t *testing.T) { err := ports.Get(context.TODO(), fake.ServiceClient(fakeServer), "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2").ExtractInto(&s) th.AssertNoErr(t, err) - th.AssertEquals(t, s.Status, "DOWN") - th.AssertEquals(t, s.Name, "private-port") - th.AssertEquals(t, s.AdminStateUp, true) - th.AssertEquals(t, s.NetworkID, "a87cc70a-3e15-4acf-8205-9b711a3531b7") - th.AssertEquals(t, s.TenantID, "d6700c0c9ffa4f1cb322cd4a1f3906fa") - th.AssertEquals(t, s.DeviceOwner, "") - th.AssertEquals(t, s.MACAddress, "fa:16:3e:c9:cb:f0") - th.AssertDeepEquals(t, s.FixedIPs, []ports.IP{ + th.AssertEquals(t, "DOWN", s.Status) + th.AssertEquals(t, "private-port", s.Name) + th.AssertEquals(t, true, s.AdminStateUp) + th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", s.NetworkID) + th.AssertEquals(t, "d6700c0c9ffa4f1cb322cd4a1f3906fa", s.TenantID) + th.AssertEquals(t, "", s.DeviceOwner) + th.AssertEquals(t, "fa:16:3e:c9:cb:f0", s.MACAddress) + th.AssertDeepEquals(t, []ports.IP{ {SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.1"}, - }) - th.AssertEquals(t, s.ID, "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2") - th.AssertEquals(t, s.DeviceID, "") + }, s.FixedIPs) + th.AssertEquals(t, "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2", s.ID) + th.AssertEquals(t, "", s.DeviceID) if s.PortTrustedVIF != nil { t.Fatalf("Expected s.PortTrustedVIF to be nil") @@ -191,18 +191,18 @@ func TestCreateWithPortTrustedVIF(t *testing.T) { err := ports.Create(context.TODO(), fake.ServiceClient(fakeServer), createOpts).ExtractInto(&portWithExt) th.AssertNoErr(t, err) - th.AssertEquals(t, portWithExt.Status, "DOWN") - th.AssertEquals(t, portWithExt.Name, "private-port") - th.AssertEquals(t, portWithExt.AdminStateUp, true) - th.AssertEquals(t, portWithExt.NetworkID, "a87cc70a-3e15-4acf-8205-9b711a3531b7") - th.AssertEquals(t, portWithExt.TenantID, "d6700c0c9ffa4f1cb322cd4a1f3906fa") - th.AssertEquals(t, portWithExt.DeviceOwner, "") - th.AssertEquals(t, portWithExt.MACAddress, "fa:16:3e:c9:cb:f0") - th.AssertDeepEquals(t, portWithExt.FixedIPs, []ports.IP{ + th.AssertEquals(t, "DOWN", portWithExt.Status) + th.AssertEquals(t, "private-port", portWithExt.Name) + th.AssertEquals(t, true, portWithExt.AdminStateUp) + th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", portWithExt.NetworkID) + th.AssertEquals(t, "d6700c0c9ffa4f1cb322cd4a1f3906fa", portWithExt.TenantID) + th.AssertEquals(t, "", portWithExt.DeviceOwner) + th.AssertEquals(t, "fa:16:3e:c9:cb:f0", portWithExt.MACAddress) + th.AssertDeepEquals(t, []ports.IP{ {SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.2"}, - }) - th.AssertEquals(t, portWithExt.ID, "65c0ee9f-d634-4522-8954-51021b570b0d") - th.AssertEquals(t, *portWithExt.PortTrustedVIF, true) + }, portWithExt.FixedIPs) + th.AssertEquals(t, "65c0ee9f-d634-4522-8954-51021b570b0d", portWithExt.ID) + th.AssertEquals(t, true, *portWithExt.PortTrustedVIF) } func TestUpdatePortTrustedVIF(t *testing.T) { @@ -237,6 +237,6 @@ func TestUpdatePortTrustedVIF(t *testing.T) { err := ports.Update(context.TODO(), fake.ServiceClient(fakeServer), "65c0ee9f-d634-4522-8954-51021b570b0d", updateOpts).ExtractInto(&portWithExt) th.AssertNoErr(t, err) - th.AssertEquals(t, portWithExt.Name, "private-port") - th.AssertDeepEquals(t, *portWithExt.PortTrustedVIF, false) + th.AssertEquals(t, "private-port", portWithExt.Name) + th.AssertDeepEquals(t, false, *portWithExt.PortTrustedVIF) } diff --git a/openstack/networking/v2/extensions/provider/testing/results_test.go b/openstack/networking/v2/extensions/provider/testing/results_test.go index c8f7874b9d..74dda0dcb0 100644 --- a/openstack/networking/v2/extensions/provider/testing/results_test.go +++ b/openstack/networking/v2/extensions/provider/testing/results_test.go @@ -44,8 +44,8 @@ func TestList(t *testing.T) { th.AssertEquals(t, "db193ab3-96e3-4cb3-8fc5-05f4296d0324", actual[1].ID) th.AssertEquals(t, "local", actual[1].NetworkType) th.AssertEquals(t, "1234567890", actual[1].SegmentationID) - th.AssertEquals(t, actual[0].Subnets[0], "54d6f61d-db07-451c-9ab3-b9609b6b6f0b") - th.AssertEquals(t, actual[1].Subnets[0], "08eae331-0402-425a-923c-34f7cfe39c1b") + th.AssertEquals(t, "54d6f61d-db07-451c-9ab3-b9609b6b6f0b", actual[0].Subnets[0]) + th.AssertEquals(t, "08eae331-0402-425a-923c-34f7cfe39c1b", actual[1].Subnets[0]) } diff --git a/openstack/networking/v2/extensions/qos/policies/testing/requests_test.go b/openstack/networking/v2/extensions/qos/policies/testing/requests_test.go index 4b84d773b8..04394bcc97 100644 --- a/openstack/networking/v2/extensions/qos/policies/testing/requests_test.go +++ b/openstack/networking/v2/extensions/qos/policies/testing/requests_test.go @@ -37,8 +37,8 @@ func TestGetPort(t *testing.T) { err := ports.Get(context.TODO(), fake.ServiceClient(fakeServer), "65c0ee9f-d634-4522-8954-51021b570b0d").ExtractInto(&p) th.AssertNoErr(t, err) - th.AssertEquals(t, p.ID, "65c0ee9f-d634-4522-8954-51021b570b0d") - th.AssertEquals(t, p.QoSPolicyID, "591e0597-39a6-4665-8149-2111d8de9a08") + th.AssertEquals(t, "65c0ee9f-d634-4522-8954-51021b570b0d", p.ID) + th.AssertEquals(t, "591e0597-39a6-4665-8149-2111d8de9a08", p.QoSPolicyID) } func TestCreatePort(t *testing.T) { @@ -73,10 +73,10 @@ func TestCreatePort(t *testing.T) { err := ports.Create(context.TODO(), fake.ServiceClient(fakeServer), createOpts).ExtractInto(&p) th.AssertNoErr(t, err) - th.AssertEquals(t, p.NetworkID, "a87cc70a-3e15-4acf-8205-9b711a3531b7") - th.AssertEquals(t, p.TenantID, "d6700c0c9ffa4f1cb322cd4a1f3906fa") - th.AssertEquals(t, p.ID, "65c0ee9f-d634-4522-8954-51021b570b0d") - th.AssertEquals(t, p.QoSPolicyID, "591e0597-39a6-4665-8149-2111d8de9a08") + th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", p.NetworkID) + th.AssertEquals(t, "d6700c0c9ffa4f1cb322cd4a1f3906fa", p.TenantID) + th.AssertEquals(t, "65c0ee9f-d634-4522-8954-51021b570b0d", p.ID) + th.AssertEquals(t, "591e0597-39a6-4665-8149-2111d8de9a08", p.QoSPolicyID) } func TestUpdatePortWithPolicy(t *testing.T) { @@ -111,10 +111,10 @@ func TestUpdatePortWithPolicy(t *testing.T) { err := ports.Update(context.TODO(), fake.ServiceClient(fakeServer), "65c0ee9f-d634-4522-8954-51021b570b0d", updateOpts).ExtractInto(&p) th.AssertNoErr(t, err) - th.AssertEquals(t, p.NetworkID, "a87cc70a-3e15-4acf-8205-9b711a3531b7") - th.AssertEquals(t, p.TenantID, "d6700c0c9ffa4f1cb322cd4a1f3906fa") - th.AssertEquals(t, p.ID, "65c0ee9f-d634-4522-8954-51021b570b0d") - th.AssertEquals(t, p.QoSPolicyID, "591e0597-39a6-4665-8149-2111d8de9a08") + th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", p.NetworkID) + th.AssertEquals(t, "d6700c0c9ffa4f1cb322cd4a1f3906fa", p.TenantID) + th.AssertEquals(t, "65c0ee9f-d634-4522-8954-51021b570b0d", p.ID) + th.AssertEquals(t, "591e0597-39a6-4665-8149-2111d8de9a08", p.QoSPolicyID) } func TestUpdatePortWithoutPolicy(t *testing.T) { @@ -149,10 +149,10 @@ func TestUpdatePortWithoutPolicy(t *testing.T) { err := ports.Update(context.TODO(), fake.ServiceClient(fakeServer), "65c0ee9f-d634-4522-8954-51021b570b0d", updateOpts).ExtractInto(&p) th.AssertNoErr(t, err) - th.AssertEquals(t, p.NetworkID, "a87cc70a-3e15-4acf-8205-9b711a3531b7") - th.AssertEquals(t, p.TenantID, "d6700c0c9ffa4f1cb322cd4a1f3906fa") - th.AssertEquals(t, p.ID, "65c0ee9f-d634-4522-8954-51021b570b0d") - th.AssertEquals(t, p.QoSPolicyID, "") + th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", p.NetworkID) + th.AssertEquals(t, "d6700c0c9ffa4f1cb322cd4a1f3906fa", p.TenantID) + th.AssertEquals(t, "65c0ee9f-d634-4522-8954-51021b570b0d", p.ID) + th.AssertEquals(t, "", p.QoSPolicyID) } func TestGetNetwork(t *testing.T) { @@ -177,8 +177,8 @@ func TestGetNetwork(t *testing.T) { err := networks.Get(context.TODO(), fake.ServiceClient(fakeServer), "65c0ee9f-d634-4522-8954-51021b570b0d").ExtractInto(&n) th.AssertNoErr(t, err) - th.AssertEquals(t, n.ID, "65c0ee9f-d634-4522-8954-51021b570b0d") - th.AssertEquals(t, n.QoSPolicyID, "591e0597-39a6-4665-8149-2111d8de9a08") + th.AssertEquals(t, "65c0ee9f-d634-4522-8954-51021b570b0d", n.ID) + th.AssertEquals(t, "591e0597-39a6-4665-8149-2111d8de9a08", n.QoSPolicyID) } func TestCreateNetwork(t *testing.T) { @@ -213,9 +213,9 @@ func TestCreateNetwork(t *testing.T) { err := networks.Create(context.TODO(), fake.ServiceClient(fakeServer), createOpts).ExtractInto(&n) th.AssertNoErr(t, err) - th.AssertEquals(t, n.TenantID, "4fd44f30292945e481c7b8a0c8908869") - th.AssertEquals(t, n.ID, "65c0ee9f-d634-4522-8954-51021b570b0d") - th.AssertEquals(t, n.QoSPolicyID, "591e0597-39a6-4665-8149-2111d8de9a08") + th.AssertEquals(t, "4fd44f30292945e481c7b8a0c8908869", n.TenantID) + th.AssertEquals(t, "65c0ee9f-d634-4522-8954-51021b570b0d", n.ID) + th.AssertEquals(t, "591e0597-39a6-4665-8149-2111d8de9a08", n.QoSPolicyID) } func TestUpdateNetworkWithPolicy(t *testing.T) { @@ -253,10 +253,10 @@ func TestUpdateNetworkWithPolicy(t *testing.T) { err := networks.Update(context.TODO(), fake.ServiceClient(fakeServer), "65c0ee9f-d634-4522-8954-51021b570b0d", updateOpts).ExtractInto(&n) th.AssertNoErr(t, err) - th.AssertEquals(t, n.TenantID, "4fd44f30292945e481c7b8a0c8908869") - th.AssertEquals(t, n.ID, "65c0ee9f-d634-4522-8954-51021b570b0d") - th.AssertEquals(t, n.Name, "updated") - th.AssertEquals(t, n.QoSPolicyID, "591e0597-39a6-4665-8149-2111d8de9a08") + th.AssertEquals(t, "4fd44f30292945e481c7b8a0c8908869", n.TenantID) + th.AssertEquals(t, "65c0ee9f-d634-4522-8954-51021b570b0d", n.ID) + th.AssertEquals(t, "updated", n.Name) + th.AssertEquals(t, "591e0597-39a6-4665-8149-2111d8de9a08", n.QoSPolicyID) } func TestUpdateNetworkWithoutPolicy(t *testing.T) { @@ -291,9 +291,9 @@ func TestUpdateNetworkWithoutPolicy(t *testing.T) { err := networks.Update(context.TODO(), fake.ServiceClient(fakeServer), "65c0ee9f-d634-4522-8954-51021b570b0d", updateOpts).ExtractInto(&n) th.AssertNoErr(t, err) - th.AssertEquals(t, n.TenantID, "4fd44f30292945e481c7b8a0c8908869") - th.AssertEquals(t, n.ID, "65c0ee9f-d634-4522-8954-51021b570b0d") - th.AssertEquals(t, n.QoSPolicyID, "") + th.AssertEquals(t, "4fd44f30292945e481c7b8a0c8908869", n.TenantID) + th.AssertEquals(t, "65c0ee9f-d634-4522-8954-51021b570b0d", n.ID) + th.AssertEquals(t, "", n.QoSPolicyID) } func TestListPolicies(t *testing.T) { diff --git a/openstack/networking/v2/extensions/qos/rules/testing/requests_test.go b/openstack/networking/v2/extensions/qos/rules/testing/requests_test.go index 0c6402d1b6..06d42908cf 100644 --- a/openstack/networking/v2/extensions/qos/rules/testing/requests_test.go +++ b/openstack/networking/v2/extensions/qos/rules/testing/requests_test.go @@ -77,10 +77,10 @@ func TestGetBandwidthLimitRule(t *testing.T) { r, err := rules.GetBandwidthLimitRule(context.TODO(), fake.ServiceClient(fakeServer), "501005fa-3b56-4061-aaca-3f24995112e1", "30a57f4a-336b-4382-8275-d708babd2241").ExtractBandwidthLimitRule() th.AssertNoErr(t, err) - th.AssertEquals(t, r.ID, "30a57f4a-336b-4382-8275-d708babd2241") - th.AssertEquals(t, r.Direction, "egress") - th.AssertEquals(t, r.MaxBurstKBps, 300) - th.AssertEquals(t, r.MaxKBps, 3000) + th.AssertEquals(t, "30a57f4a-336b-4382-8275-d708babd2241", r.ID) + th.AssertEquals(t, "egress", r.Direction) + th.AssertEquals(t, 300, r.MaxBurstKBps) + th.AssertEquals(t, 3000, r.MaxKBps) } func TestCreateBandwidthLimitRule(t *testing.T) { @@ -218,7 +218,7 @@ func TestGetDSCPMarkingRule(t *testing.T) { r, err := rules.GetDSCPMarkingRule(context.TODO(), fake.ServiceClient(fakeServer), "501005fa-3b56-4061-aaca-3f24995112e1", "30a57f4a-336b-4382-8275-d708babd2241").ExtractDSCPMarkingRule() th.AssertNoErr(t, err) - th.AssertEquals(t, r.ID, "30a57f4a-336b-4382-8275-d708babd2241") + th.AssertEquals(t, "30a57f4a-336b-4382-8275-d708babd2241", r.ID) th.AssertEquals(t, 26, r.DSCPMark) } @@ -355,9 +355,9 @@ func TestGetMinimumBandwidthRule(t *testing.T) { r, err := rules.GetMinimumBandwidthRule(context.TODO(), fake.ServiceClient(fakeServer), "501005fa-3b56-4061-aaca-3f24995112e1", "30a57f4a-336b-4382-8275-d708babd2241").ExtractMinimumBandwidthRule() th.AssertNoErr(t, err) - th.AssertEquals(t, r.ID, "30a57f4a-336b-4382-8275-d708babd2241") - th.AssertEquals(t, r.Direction, "egress") - th.AssertEquals(t, r.MinKBps, 3000) + th.AssertEquals(t, "30a57f4a-336b-4382-8275-d708babd2241", r.ID) + th.AssertEquals(t, "egress", r.Direction) + th.AssertEquals(t, 3000, r.MinKBps) } func TestCreateMinimumBandwidthRule(t *testing.T) { diff --git a/openstack/networking/v2/extensions/rbacpolicies/testing/requests_test.go b/openstack/networking/v2/extensions/rbacpolicies/testing/requests_test.go index 68cba4a15d..e4f9558521 100644 --- a/openstack/networking/v2/extensions/rbacpolicies/testing/requests_test.go +++ b/openstack/networking/v2/extensions/rbacpolicies/testing/requests_test.go @@ -123,11 +123,11 @@ func TestListWithAllPages(t *testing.T) { err = rbacpolicies.ExtractRBACPolicesInto(allPages, &allRBACpolicies) th.AssertNoErr(t, err) - th.AssertEquals(t, allRBACpolicies[0].ObjectType, "network") + th.AssertEquals(t, "network", allRBACpolicies[0].ObjectType) th.AssertEquals(t, allRBACpolicies[0].Action, rbacpolicies.ActionAccessShared) - th.AssertEquals(t, allRBACpolicies[1].ProjectID, "1ae27ce0a2a54cc6ae06dc62dd0ec832") - th.AssertEquals(t, allRBACpolicies[1].TargetTenant, "1a547a3bcfe44702889fdeff3c3520c3") + th.AssertEquals(t, "1ae27ce0a2a54cc6ae06dc62dd0ec832", allRBACpolicies[1].ProjectID) + th.AssertEquals(t, "1a547a3bcfe44702889fdeff3c3520c3", allRBACpolicies[1].TargetTenant) } @@ -166,6 +166,6 @@ func TestUpdate(t *testing.T) { rbacResult, err := rbacpolicies.Update(context.TODO(), fake.ServiceClient(fakeServer), "2cf7523a-93b5-4e69-9360-6c6bf986bb7c", options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, rbacResult.TargetTenant, "9d766060b6354c9e8e2da44cab0e8f38") - th.AssertEquals(t, rbacResult.ID, "2cf7523a-93b5-4e69-9360-6c6bf986bb7c") + th.AssertEquals(t, "9d766060b6354c9e8e2da44cab0e8f38", rbacResult.TargetTenant) + th.AssertEquals(t, "2cf7523a-93b5-4e69-9360-6c6bf986bb7c", rbacResult.ID) } diff --git a/openstack/networking/v2/extensions/subnetpools/testing/requests_test.go b/openstack/networking/v2/extensions/subnetpools/testing/requests_test.go index 8520ef1103..7089f74726 100644 --- a/openstack/networking/v2/extensions/subnetpools/testing/requests_test.go +++ b/openstack/networking/v2/extensions/subnetpools/testing/requests_test.go @@ -72,25 +72,25 @@ func TestGet(t *testing.T) { s, err := subnetpools.Get(context.TODO(), fake.ServiceClient(fakeServer), "0a738452-8057-4ad3-89c2-92f6a74afa76").Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, s.ID, "0a738452-8057-4ad3-89c2-92f6a74afa76") - th.AssertEquals(t, s.Name, "my-ipv6-pool") - th.AssertEquals(t, s.DefaultQuota, 2) - th.AssertEquals(t, s.TenantID, "1e2b9857295a4a3e841809ef492812c5") - th.AssertEquals(t, s.ProjectID, "1e2b9857295a4a3e841809ef492812c5") + th.AssertEquals(t, "0a738452-8057-4ad3-89c2-92f6a74afa76", s.ID) + th.AssertEquals(t, "my-ipv6-pool", s.Name) + th.AssertEquals(t, 2, s.DefaultQuota) + th.AssertEquals(t, "1e2b9857295a4a3e841809ef492812c5", s.TenantID) + th.AssertEquals(t, "1e2b9857295a4a3e841809ef492812c5", s.ProjectID) th.AssertEquals(t, s.CreatedAt, time.Date(2018, 1, 1, 0, 0, 1, 0, time.UTC)) th.AssertEquals(t, s.UpdatedAt, time.Date(2018, 1, 1, 0, 10, 10, 0, time.UTC)) - th.AssertDeepEquals(t, s.Prefixes, []string{ + th.AssertDeepEquals(t, []string{ "2001:db8::a3/64", - }) - th.AssertEquals(t, s.DefaultPrefixLen, 64) - th.AssertEquals(t, s.MinPrefixLen, 64) - th.AssertEquals(t, s.MaxPrefixLen, 128) - th.AssertEquals(t, s.AddressScopeID, "") - th.AssertEquals(t, s.IPversion, 6) - th.AssertEquals(t, s.Shared, false) - th.AssertEquals(t, s.Description, "ipv6 prefixes") - th.AssertEquals(t, s.IsDefault, true) - th.AssertEquals(t, s.RevisionNumber, 2) + }, s.Prefixes) + th.AssertEquals(t, 64, s.DefaultPrefixLen) + th.AssertEquals(t, 64, s.MinPrefixLen) + th.AssertEquals(t, 128, s.MaxPrefixLen) + th.AssertEquals(t, "", s.AddressScopeID) + th.AssertEquals(t, 6, s.IPversion) + th.AssertEquals(t, false, s.Shared) + th.AssertEquals(t, "ipv6 prefixes", s.Description) + th.AssertEquals(t, true, s.IsDefault) + th.AssertEquals(t, 2, s.RevisionNumber) } func TestCreate(t *testing.T) { fakeServer := th.SetupHTTP() @@ -123,15 +123,15 @@ func TestCreate(t *testing.T) { s, err := subnetpools.Create(context.TODO(), fake.ServiceClient(fakeServer), opts).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, s.Name, "my_ipv4_pool") - th.AssertDeepEquals(t, s.Prefixes, []string{ + th.AssertEquals(t, "my_ipv4_pool", s.Name) + th.AssertDeepEquals(t, []string{ "10.10.0.0/16", "10.11.11.0/24", - }) - th.AssertEquals(t, s.MinPrefixLen, 25) - th.AssertEquals(t, s.MaxPrefixLen, 30) - th.AssertEquals(t, s.AddressScopeID, "3d4e2e2a-552b-42ad-a16d-820bbf3edaf3") - th.AssertEquals(t, s.Description, "ipv4 prefixes") + }, s.Prefixes) + th.AssertEquals(t, 25, s.MinPrefixLen) + th.AssertEquals(t, 30, s.MaxPrefixLen) + th.AssertEquals(t, "3d4e2e2a-552b-42ad-a16d-820bbf3edaf3", s.AddressScopeID) + th.AssertEquals(t, "ipv4 prefixes", s.Description) } func TestUpdate(t *testing.T) { @@ -167,17 +167,17 @@ func TestUpdate(t *testing.T) { n, err := subnetpools.Update(context.TODO(), fake.ServiceClient(fakeServer), "099546ca-788d-41e5-a76d-17d8cd282d3e", updateOpts).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.Name, "new_subnetpool_name") - th.AssertDeepEquals(t, n.Prefixes, []string{ + th.AssertEquals(t, "new_subnetpool_name", n.Name) + th.AssertDeepEquals(t, []string{ "10.8.0.0/16", "10.11.12.0/24", "10.24.0.0/16", - }) - th.AssertEquals(t, n.MaxPrefixLen, 16) - th.AssertEquals(t, n.ID, "099546ca-788d-41e5-a76d-17d8cd282d3e") - th.AssertEquals(t, n.AddressScopeID, "") - th.AssertEquals(t, n.DefaultQuota, 0) - th.AssertEquals(t, n.Description, "") + }, n.Prefixes) + th.AssertEquals(t, 16, n.MaxPrefixLen) + th.AssertEquals(t, "099546ca-788d-41e5-a76d-17d8cd282d3e", n.ID) + th.AssertEquals(t, "", n.AddressScopeID) + th.AssertEquals(t, 0, n.DefaultQuota) + th.AssertEquals(t, "", n.Description) } func TestDelete(t *testing.T) { diff --git a/openstack/networking/v2/extensions/testing/delegate_test.go b/openstack/networking/v2/extensions/testing/delegate_test.go index 95fa8461d3..5f54a099f0 100644 --- a/openstack/networking/v2/extensions/testing/delegate_test.go +++ b/openstack/networking/v2/extensions/testing/delegate_test.go @@ -100,9 +100,9 @@ func TestGet(t *testing.T) { ext, err := extensions.Get(context.TODO(), fake.ServiceClient(fakeServer), "agent").Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, ext.Updated, "2013-02-03T10:00:00-00:00") - th.AssertEquals(t, ext.Name, "agent") - th.AssertEquals(t, ext.Namespace, "http://docs.openstack.org/ext/agent/api/v2.0") - th.AssertEquals(t, ext.Alias, "agent") - th.AssertEquals(t, ext.Description, "The agent management extension.") + th.AssertEquals(t, "2013-02-03T10:00:00-00:00", ext.Updated) + th.AssertEquals(t, "agent", ext.Name) + th.AssertEquals(t, "http://docs.openstack.org/ext/agent/api/v2.0", ext.Namespace) + th.AssertEquals(t, "agent", ext.Alias) + th.AssertEquals(t, "The agent management extension.", ext.Description) } diff --git a/openstack/networking/v2/extensions/trunk_details/testing/requests_test.go b/openstack/networking/v2/extensions/trunk_details/testing/requests_test.go index f9f3c74ab7..fee71b7641 100644 --- a/openstack/networking/v2/extensions/trunk_details/testing/requests_test.go +++ b/openstack/networking/v2/extensions/trunk_details/testing/requests_test.go @@ -35,11 +35,11 @@ func TestServerWithUsageExt(t *testing.T) { err := ports.Get(context.TODO(), client.ServiceClient(fakeServer), portIDFixture).ExtractInto(&portExt) th.AssertNoErr(t, err) - th.AssertEquals(t, portExt.TrunkID, "f170c831-8c55-4ceb-ad13-75eab4a121e5") - th.AssertEquals(t, len(portExt.SubPorts), 1) + th.AssertEquals(t, "f170c831-8c55-4ceb-ad13-75eab4a121e5", portExt.TrunkID) + th.AssertEquals(t, 1, len(portExt.SubPorts)) subPort := portExt.SubPorts[0] - th.AssertEquals(t, subPort.SegmentationID, 100) - th.AssertEquals(t, subPort.SegmentationType, "vlan") - th.AssertEquals(t, subPort.PortID, "20c673d8-7f9d-4570-b662-148d9ddcc5bd") - th.AssertEquals(t, subPort.MACAddress, "fa:16:3e:88:29:a0") + th.AssertEquals(t, 100, subPort.SegmentationID) + th.AssertEquals(t, "vlan", subPort.SegmentationType) + th.AssertEquals(t, "20c673d8-7f9d-4570-b662-148d9ddcc5bd", subPort.PortID) + th.AssertEquals(t, "fa:16:3e:88:29:a0", subPort.MACAddress) } diff --git a/openstack/networking/v2/extensions/trunks/testing/requests_test.go b/openstack/networking/v2/extensions/trunks/testing/requests_test.go index 955a549f57..162226dc2a 100644 --- a/openstack/networking/v2/extensions/trunks/testing/requests_test.go +++ b/openstack/networking/v2/extensions/trunks/testing/requests_test.go @@ -54,7 +54,7 @@ func TestCreate(t *testing.T) { n, err := trunks.Create(context.TODO(), fake.ServiceClient(fakeServer), options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.Status, "ACTIVE") + th.AssertEquals(t, "ACTIVE", n.Status) expectedTrunks, err := ExpectedTrunkSlice() th.AssertNoErr(t, err) th.AssertDeepEquals(t, &expectedTrunks[1], n) @@ -86,7 +86,7 @@ func TestCreateNoSubports(t *testing.T) { n, err := trunks.Create(context.TODO(), fake.ServiceClient(fakeServer), options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.Status, "ACTIVE") + th.AssertEquals(t, "ACTIVE", n.Status) th.AssertEquals(t, 0, len(n.Subports)) } diff --git a/openstack/networking/v2/networks/testing/requests_test.go b/openstack/networking/v2/networks/testing/requests_test.go index bd87758699..4d5bcc66d6 100644 --- a/openstack/networking/v2/networks/testing/requests_test.go +++ b/openstack/networking/v2/networks/testing/requests_test.go @@ -80,14 +80,14 @@ func TestListWithExtensions(t *testing.T) { err = networks.ExtractNetworksInto(allPages, &allNetworks) th.AssertNoErr(t, err) - th.AssertEquals(t, allNetworks[0].Status, "ACTIVE") - th.AssertEquals(t, allNetworks[0].PortSecurityEnabled, true) - th.AssertEquals(t, allNetworks[0].Subnets[0], "54d6f61d-db07-451c-9ab3-b9609b6b6f0b") - th.AssertEquals(t, allNetworks[1].Subnets[0], "08eae331-0402-425a-923c-34f7cfe39c1b") - th.AssertEquals(t, allNetworks[0].CreatedAt.Format(time.RFC3339), "2019-06-30T04:15:37Z") - th.AssertEquals(t, allNetworks[0].UpdatedAt.Format(time.RFC3339), "2019-06-30T05:18:49Z") - th.AssertEquals(t, allNetworks[1].CreatedAt.Format(time.RFC3339), "2019-06-30T04:15:37Z") - th.AssertEquals(t, allNetworks[1].UpdatedAt.Format(time.RFC3339), "2019-06-30T05:18:49Z") + th.AssertEquals(t, "ACTIVE", allNetworks[0].Status) + th.AssertEquals(t, true, allNetworks[0].PortSecurityEnabled) + th.AssertEquals(t, "54d6f61d-db07-451c-9ab3-b9609b6b6f0b", allNetworks[0].Subnets[0]) + th.AssertEquals(t, "08eae331-0402-425a-923c-34f7cfe39c1b", allNetworks[1].Subnets[0]) + th.AssertEquals(t, "2019-06-30T04:15:37Z", allNetworks[0].CreatedAt.Format(time.RFC3339)) + th.AssertEquals(t, "2019-06-30T05:18:49Z", allNetworks[0].UpdatedAt.Format(time.RFC3339)) + th.AssertEquals(t, "2019-06-30T04:15:37Z", allNetworks[1].CreatedAt.Format(time.RFC3339)) + th.AssertEquals(t, "2019-06-30T05:18:49Z", allNetworks[1].UpdatedAt.Format(time.RFC3339)) } func TestGet(t *testing.T) { @@ -107,8 +107,8 @@ func TestGet(t *testing.T) { n, err := networks.Get(context.TODO(), fake.ServiceClient(fakeServer), "d32019d3-bc6e-4319-9c1d-6722fc136a22").Extract() th.AssertNoErr(t, err) th.CheckDeepEquals(t, &Network1, n) - th.AssertEquals(t, n.CreatedAt.Format(time.RFC3339), "2019-06-30T04:15:37Z") - th.AssertEquals(t, n.UpdatedAt.Format(time.RFC3339), "2019-06-30T05:18:49Z") + th.AssertEquals(t, "2019-06-30T04:15:37Z", n.CreatedAt.Format(time.RFC3339)) + th.AssertEquals(t, "2019-06-30T05:18:49Z", n.UpdatedAt.Format(time.RFC3339)) } func TestGetWithExtensions(t *testing.T) { @@ -133,8 +133,8 @@ func TestGetWithExtensions(t *testing.T) { err := networks.Get(context.TODO(), fake.ServiceClient(fakeServer), "d32019d3-bc6e-4319-9c1d-6722fc136a22").ExtractInto(&networkWithExtensions) th.AssertNoErr(t, err) - th.AssertEquals(t, networkWithExtensions.Status, "ACTIVE") - th.AssertEquals(t, networkWithExtensions.PortSecurityEnabled, true) + th.AssertEquals(t, "ACTIVE", networkWithExtensions.Status) + th.AssertEquals(t, true, networkWithExtensions.PortSecurityEnabled) } func TestCreate(t *testing.T) { @@ -158,10 +158,10 @@ func TestCreate(t *testing.T) { n, err := networks.Create(context.TODO(), fake.ServiceClient(fakeServer), options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.Status, "ACTIVE") + th.AssertEquals(t, "ACTIVE", n.Status) th.AssertDeepEquals(t, &Network2, n) - th.AssertEquals(t, n.CreatedAt.Format(time.RFC3339), "2019-06-30T04:15:37Z") - th.AssertEquals(t, n.UpdatedAt.Format(time.RFC3339), "2019-06-30T05:18:49Z") + th.AssertEquals(t, "2019-06-30T04:15:37Z", n.CreatedAt.Format(time.RFC3339)) + th.AssertEquals(t, "2019-06-30T05:18:49Z", n.UpdatedAt.Format(time.RFC3339)) } func TestCreateWithOptionalFields(t *testing.T) { @@ -214,12 +214,12 @@ func TestUpdate(t *testing.T) { n, err := networks.Update(context.TODO(), fake.ServiceClient(fakeServer), "4e8e5957-649f-477b-9e5b-f1f75b21c03c", options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.Name, "new_network_name") - th.AssertEquals(t, n.AdminStateUp, false) - th.AssertEquals(t, n.Shared, true) - th.AssertEquals(t, n.ID, "4e8e5957-649f-477b-9e5b-f1f75b21c03c") - th.AssertEquals(t, n.CreatedAt.Format(time.RFC3339), "2019-06-30T04:15:37Z") - th.AssertEquals(t, n.UpdatedAt.Format(time.RFC3339), "2019-06-30T05:18:49Z") + th.AssertEquals(t, "new_network_name", n.Name) + th.AssertEquals(t, false, n.AdminStateUp) + th.AssertEquals(t, true, n.Shared) + th.AssertEquals(t, "4e8e5957-649f-477b-9e5b-f1f75b21c03c", n.ID) + th.AssertEquals(t, "2019-06-30T04:15:37Z", n.CreatedAt.Format(time.RFC3339)) + th.AssertEquals(t, "2019-06-30T05:18:49Z", n.UpdatedAt.Format(time.RFC3339)) } func TestUpdateRevision(t *testing.T) { @@ -312,8 +312,8 @@ func TestCreatePortSecurity(t *testing.T) { err := networks.Create(context.TODO(), fake.ServiceClient(fakeServer), createOpts).ExtractInto(&networkWithExtensions) th.AssertNoErr(t, err) - th.AssertEquals(t, networkWithExtensions.Status, "ACTIVE") - th.AssertEquals(t, networkWithExtensions.PortSecurityEnabled, false) + th.AssertEquals(t, "ACTIVE", networkWithExtensions.Status) + th.AssertEquals(t, false, networkWithExtensions.PortSecurityEnabled) } func TestUpdatePortSecurity(t *testing.T) { @@ -348,9 +348,9 @@ func TestUpdatePortSecurity(t *testing.T) { err := networks.Update(context.TODO(), fake.ServiceClient(fakeServer), "4e8e5957-649f-477b-9e5b-f1f75b21c03c", updateOpts).ExtractInto(&networkWithExtensions) th.AssertNoErr(t, err) - th.AssertEquals(t, networkWithExtensions.Name, "private") - th.AssertEquals(t, networkWithExtensions.AdminStateUp, true) - th.AssertEquals(t, networkWithExtensions.Shared, false) - th.AssertEquals(t, networkWithExtensions.ID, "4e8e5957-649f-477b-9e5b-f1f75b21c03c") - th.AssertEquals(t, networkWithExtensions.PortSecurityEnabled, false) + th.AssertEquals(t, "private", networkWithExtensions.Name) + th.AssertEquals(t, true, networkWithExtensions.AdminStateUp) + th.AssertEquals(t, false, networkWithExtensions.Shared) + th.AssertEquals(t, "4e8e5957-649f-477b-9e5b-f1f75b21c03c", networkWithExtensions.ID) + th.AssertEquals(t, false, networkWithExtensions.PortSecurityEnabled) } diff --git a/openstack/networking/v2/ports/testing/requests_test.go b/openstack/networking/v2/ports/testing/requests_test.go index f69962f74b..112f7deab5 100644 --- a/openstack/networking/v2/ports/testing/requests_test.go +++ b/openstack/networking/v2/ports/testing/requests_test.go @@ -102,8 +102,8 @@ func TestListWithExtensions(t *testing.T) { err = ports.ExtractPortsInto(allPages, &allPorts) th.AssertNoErr(t, err) - th.AssertEquals(t, allPorts[0].Status, "ACTIVE") - th.AssertEquals(t, allPorts[0].PortSecurityEnabled, false) + th.AssertEquals(t, "ACTIVE", allPorts[0].Status) + th.AssertEquals(t, false, allPorts[0].PortSecurityEnabled) } func TestGet(t *testing.T) { @@ -123,20 +123,20 @@ func TestGet(t *testing.T) { n, err := ports.Get(context.TODO(), fake.ServiceClient(fakeServer), "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2").Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.Status, "ACTIVE") - th.AssertEquals(t, n.Name, "") - th.AssertEquals(t, n.AdminStateUp, true) - th.AssertEquals(t, n.NetworkID, "a87cc70a-3e15-4acf-8205-9b711a3531b7") - th.AssertEquals(t, n.TenantID, "7e02058126cc4950b75f9970368ba177") - th.AssertEquals(t, n.DeviceOwner, "network:router_interface") - th.AssertEquals(t, n.MACAddress, "fa:16:3e:23:fd:d7") - th.AssertDeepEquals(t, n.FixedIPs, []ports.IP{ + th.AssertEquals(t, "ACTIVE", n.Status) + th.AssertEquals(t, "", n.Name) + th.AssertEquals(t, true, n.AdminStateUp) + th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", n.NetworkID) + th.AssertEquals(t, "7e02058126cc4950b75f9970368ba177", n.TenantID) + th.AssertEquals(t, "network:router_interface", n.DeviceOwner) + th.AssertEquals(t, "fa:16:3e:23:fd:d7", n.MACAddress) + th.AssertDeepEquals(t, []ports.IP{ {SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.1"}, - }) - th.AssertEquals(t, n.ID, "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2") - th.AssertDeepEquals(t, n.SecurityGroups, []string{}) - th.AssertEquals(t, n.Status, "ACTIVE") - th.AssertEquals(t, n.DeviceID, "5e3898d7-11be-483e-9732-b2f5eccd2b2e") + }, n.FixedIPs) + th.AssertEquals(t, "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2", n.ID) + th.AssertDeepEquals(t, []string{}, n.SecurityGroups) + th.AssertEquals(t, "ACTIVE", n.Status) + th.AssertEquals(t, "5e3898d7-11be-483e-9732-b2f5eccd2b2e", n.DeviceID) th.AssertEquals(t, n.CreatedAt, time.Date(2019, time.June, 30, 4, 15, 37, 0, time.UTC)) th.AssertEquals(t, n.UpdatedAt, time.Date(2019, time.June, 30, 5, 18, 49, 0, time.UTC)) } @@ -163,8 +163,8 @@ func TestGetWithExtensions(t *testing.T) { err := ports.Get(context.TODO(), fake.ServiceClient(fakeServer), "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2").ExtractInto(&portWithExtensions) th.AssertNoErr(t, err) - th.AssertEquals(t, portWithExtensions.Status, "ACTIVE") - th.AssertEquals(t, portWithExtensions.PortSecurityEnabled, false) + th.AssertEquals(t, "ACTIVE", portWithExtensions.Status) + th.AssertEquals(t, false, portWithExtensions.PortSecurityEnabled) } func TestCreate(t *testing.T) { @@ -200,21 +200,21 @@ func TestCreate(t *testing.T) { n, err := ports.Create(context.TODO(), fake.ServiceClient(fakeServer), options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.Status, "DOWN") - th.AssertEquals(t, n.Name, "private-port") - th.AssertEquals(t, n.AdminStateUp, true) - th.AssertEquals(t, n.NetworkID, "a87cc70a-3e15-4acf-8205-9b711a3531b7") - th.AssertEquals(t, n.TenantID, "d6700c0c9ffa4f1cb322cd4a1f3906fa") - th.AssertEquals(t, n.DeviceOwner, "") - th.AssertEquals(t, n.MACAddress, "fa:16:3e:c9:cb:f0") - th.AssertDeepEquals(t, n.FixedIPs, []ports.IP{ + th.AssertEquals(t, "DOWN", n.Status) + th.AssertEquals(t, "private-port", n.Name) + th.AssertEquals(t, true, n.AdminStateUp) + th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", n.NetworkID) + th.AssertEquals(t, "d6700c0c9ffa4f1cb322cd4a1f3906fa", n.TenantID) + th.AssertEquals(t, "", n.DeviceOwner) + th.AssertEquals(t, "fa:16:3e:c9:cb:f0", n.MACAddress) + th.AssertDeepEquals(t, []ports.IP{ {SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.2"}, - }) - th.AssertEquals(t, n.ID, "65c0ee9f-d634-4522-8954-51021b570b0d") - th.AssertDeepEquals(t, n.SecurityGroups, []string{"f0ac4394-7e4a-4409-9701-ba8be283dbc3"}) - th.AssertDeepEquals(t, n.AllowedAddressPairs, []ports.AddressPair{ + }, n.FixedIPs) + th.AssertEquals(t, "65c0ee9f-d634-4522-8954-51021b570b0d", n.ID) + th.AssertDeepEquals(t, []string{"f0ac4394-7e4a-4409-9701-ba8be283dbc3"}, n.SecurityGroups) + th.AssertDeepEquals(t, []ports.AddressPair{ {IPAddress: "10.0.0.4", MACAddress: "fa:16:3e:c9:cb:f0"}, - }) + }, n.AllowedAddressPairs) } func TestCreateOmitSecurityGroups(t *testing.T) { @@ -249,21 +249,21 @@ func TestCreateOmitSecurityGroups(t *testing.T) { n, err := ports.Create(context.TODO(), fake.ServiceClient(fakeServer), options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.Status, "DOWN") - th.AssertEquals(t, n.Name, "private-port") - th.AssertEquals(t, n.AdminStateUp, true) - th.AssertEquals(t, n.NetworkID, "a87cc70a-3e15-4acf-8205-9b711a3531b7") - th.AssertEquals(t, n.TenantID, "d6700c0c9ffa4f1cb322cd4a1f3906fa") - th.AssertEquals(t, n.DeviceOwner, "") - th.AssertEquals(t, n.MACAddress, "fa:16:3e:c9:cb:f0") - th.AssertDeepEquals(t, n.FixedIPs, []ports.IP{ + th.AssertEquals(t, "DOWN", n.Status) + th.AssertEquals(t, "private-port", n.Name) + th.AssertEquals(t, true, n.AdminStateUp) + th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", n.NetworkID) + th.AssertEquals(t, "d6700c0c9ffa4f1cb322cd4a1f3906fa", n.TenantID) + th.AssertEquals(t, "", n.DeviceOwner) + th.AssertEquals(t, "fa:16:3e:c9:cb:f0", n.MACAddress) + th.AssertDeepEquals(t, []ports.IP{ {SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.2"}, - }) - th.AssertEquals(t, n.ID, "65c0ee9f-d634-4522-8954-51021b570b0d") - th.AssertDeepEquals(t, n.SecurityGroups, []string{"f0ac4394-7e4a-4409-9701-ba8be283dbc3"}) - th.AssertDeepEquals(t, n.AllowedAddressPairs, []ports.AddressPair{ + }, n.FixedIPs) + th.AssertEquals(t, "65c0ee9f-d634-4522-8954-51021b570b0d", n.ID) + th.AssertDeepEquals(t, []string{"f0ac4394-7e4a-4409-9701-ba8be283dbc3"}, n.SecurityGroups) + th.AssertDeepEquals(t, []ports.AddressPair{ {IPAddress: "10.0.0.4", MACAddress: "fa:16:3e:c9:cb:f0"}, - }) + }, n.AllowedAddressPairs) } func TestCreateWithNoSecurityGroup(t *testing.T) { @@ -299,20 +299,20 @@ func TestCreateWithNoSecurityGroup(t *testing.T) { n, err := ports.Create(context.TODO(), fake.ServiceClient(fakeServer), options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.Status, "DOWN") - th.AssertEquals(t, n.Name, "private-port") - th.AssertEquals(t, n.AdminStateUp, true) - th.AssertEquals(t, n.NetworkID, "a87cc70a-3e15-4acf-8205-9b711a3531b7") - th.AssertEquals(t, n.TenantID, "d6700c0c9ffa4f1cb322cd4a1f3906fa") - th.AssertEquals(t, n.DeviceOwner, "") - th.AssertEquals(t, n.MACAddress, "fa:16:3e:c9:cb:f0") - th.AssertDeepEquals(t, n.FixedIPs, []ports.IP{ + th.AssertEquals(t, "DOWN", n.Status) + th.AssertEquals(t, "private-port", n.Name) + th.AssertEquals(t, true, n.AdminStateUp) + th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", n.NetworkID) + th.AssertEquals(t, "d6700c0c9ffa4f1cb322cd4a1f3906fa", n.TenantID) + th.AssertEquals(t, "", n.DeviceOwner) + th.AssertEquals(t, "fa:16:3e:c9:cb:f0", n.MACAddress) + th.AssertDeepEquals(t, []ports.IP{ {SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.2"}, - }) - th.AssertEquals(t, n.ID, "65c0ee9f-d634-4522-8954-51021b570b0d") - th.AssertDeepEquals(t, n.AllowedAddressPairs, []ports.AddressPair{ + }, n.FixedIPs) + th.AssertEquals(t, "65c0ee9f-d634-4522-8954-51021b570b0d", n.ID) + th.AssertDeepEquals(t, []ports.AddressPair{ {IPAddress: "10.0.0.4", MACAddress: "fa:16:3e:c9:cb:f0"}, - }) + }, n.AllowedAddressPairs) } func TestCreateWithPropagateUplinkStatus(t *testing.T) { @@ -346,17 +346,17 @@ func TestCreateWithPropagateUplinkStatus(t *testing.T) { n, err := ports.Create(context.TODO(), fake.ServiceClient(fakeServer), options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.Status, "DOWN") - th.AssertEquals(t, n.Name, "private-port") - th.AssertEquals(t, n.AdminStateUp, true) - th.AssertEquals(t, n.NetworkID, "a87cc70a-3e15-4acf-8205-9b711a3531b7") - th.AssertEquals(t, n.TenantID, "d6700c0c9ffa4f1cb322cd4a1f3906fa") - th.AssertEquals(t, n.DeviceOwner, "") - th.AssertEquals(t, n.MACAddress, "fa:16:3e:c9:cb:f0") - th.AssertDeepEquals(t, n.FixedIPs, []ports.IP{ + th.AssertEquals(t, "DOWN", n.Status) + th.AssertEquals(t, "private-port", n.Name) + th.AssertEquals(t, true, n.AdminStateUp) + th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", n.NetworkID) + th.AssertEquals(t, "d6700c0c9ffa4f1cb322cd4a1f3906fa", n.TenantID) + th.AssertEquals(t, "", n.DeviceOwner) + th.AssertEquals(t, "fa:16:3e:c9:cb:f0", n.MACAddress) + th.AssertDeepEquals(t, []ports.IP{ {SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.2"}, - }) - th.AssertEquals(t, n.ID, "65c0ee9f-d634-4522-8954-51021b570b0d") + }, n.FixedIPs) + th.AssertEquals(t, "65c0ee9f-d634-4522-8954-51021b570b0d", n.ID) th.AssertEquals(t, n.PropagateUplinkStatus, propagateUplinkStatus) } @@ -396,21 +396,21 @@ func TestCreateWithValueSpecs(t *testing.T) { n, err := ports.Create(context.TODO(), fake.ServiceClient(fakeServer), options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.Status, "DOWN") - th.AssertEquals(t, n.Name, "private-port") - th.AssertEquals(t, n.AdminStateUp, true) - th.AssertEquals(t, n.NetworkID, "a87cc70a-3e15-4acf-8205-9b711a3531b7") - th.AssertEquals(t, n.TenantID, "d6700c0c9ffa4f1cb322cd4a1f3906fa") - th.AssertEquals(t, n.DeviceOwner, "") - th.AssertEquals(t, n.MACAddress, "fa:16:3e:c9:cb:f0") - th.AssertDeepEquals(t, n.FixedIPs, []ports.IP{ + th.AssertEquals(t, "DOWN", n.Status) + th.AssertEquals(t, "private-port", n.Name) + th.AssertEquals(t, true, n.AdminStateUp) + th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", n.NetworkID) + th.AssertEquals(t, "d6700c0c9ffa4f1cb322cd4a1f3906fa", n.TenantID) + th.AssertEquals(t, "", n.DeviceOwner) + th.AssertEquals(t, "fa:16:3e:c9:cb:f0", n.MACAddress) + th.AssertDeepEquals(t, []ports.IP{ {SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.2"}, - }) - th.AssertEquals(t, n.ID, "65c0ee9f-d634-4522-8954-51021b570b0d") - th.AssertDeepEquals(t, n.SecurityGroups, []string{"f0ac4394-7e4a-4409-9701-ba8be283dbc3"}) - th.AssertDeepEquals(t, n.AllowedAddressPairs, []ports.AddressPair{ + }, n.FixedIPs) + th.AssertEquals(t, "65c0ee9f-d634-4522-8954-51021b570b0d", n.ID) + th.AssertDeepEquals(t, []string{"f0ac4394-7e4a-4409-9701-ba8be283dbc3"}, n.SecurityGroups) + th.AssertDeepEquals(t, []ports.AddressPair{ {IPAddress: "10.0.0.4", MACAddress: "fa:16:3e:c9:cb:f0"}, - }) + }, n.AllowedAddressPairs) } func TestCreateWithInvalidValueSpecs(t *testing.T) { @@ -516,8 +516,8 @@ func TestCreatePortSecurity(t *testing.T) { err := ports.Create(context.TODO(), fake.ServiceClient(fakeServer), createOpts).ExtractInto(&portWithExt) th.AssertNoErr(t, err) - th.AssertEquals(t, portWithExt.Status, "DOWN") - th.AssertEquals(t, portWithExt.PortSecurityEnabled, false) + th.AssertEquals(t, "DOWN", portWithExt.Status) + th.AssertEquals(t, false, portWithExt.PortSecurityEnabled) } func TestUpdate(t *testing.T) { @@ -554,14 +554,14 @@ func TestUpdate(t *testing.T) { s, err := ports.Update(context.TODO(), fake.ServiceClient(fakeServer), "65c0ee9f-d634-4522-8954-51021b570b0d", options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, s.Name, "new_port_name") - th.AssertDeepEquals(t, s.FixedIPs, []ports.IP{ + th.AssertEquals(t, "new_port_name", s.Name) + th.AssertDeepEquals(t, []ports.IP{ {SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.3"}, - }) - th.AssertDeepEquals(t, s.AllowedAddressPairs, []ports.AddressPair{ + }, s.FixedIPs) + th.AssertDeepEquals(t, []ports.AddressPair{ {IPAddress: "10.0.0.4", MACAddress: "fa:16:3e:c9:cb:f0"}, - }) - th.AssertDeepEquals(t, s.SecurityGroups, []string{"f0ac4394-7e4a-4409-9701-ba8be283dbc3"}) + }, s.AllowedAddressPairs) + th.AssertDeepEquals(t, []string{"f0ac4394-7e4a-4409-9701-ba8be283dbc3"}, s.SecurityGroups) } func TestUpdateOmitSecurityGroups(t *testing.T) { @@ -595,14 +595,14 @@ func TestUpdateOmitSecurityGroups(t *testing.T) { s, err := ports.Update(context.TODO(), fake.ServiceClient(fakeServer), "65c0ee9f-d634-4522-8954-51021b570b0d", options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, s.Name, "new_port_name") - th.AssertDeepEquals(t, s.FixedIPs, []ports.IP{ + th.AssertEquals(t, "new_port_name", s.Name) + th.AssertDeepEquals(t, []ports.IP{ {SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.3"}, - }) - th.AssertDeepEquals(t, s.AllowedAddressPairs, []ports.AddressPair{ + }, s.FixedIPs) + th.AssertDeepEquals(t, []ports.AddressPair{ {IPAddress: "10.0.0.4", MACAddress: "fa:16:3e:c9:cb:f0"}, - }) - th.AssertDeepEquals(t, s.SecurityGroups, []string{"f0ac4394-7e4a-4409-9701-ba8be283dbc3"}) + }, s.AllowedAddressPairs) + th.AssertDeepEquals(t, []string{"f0ac4394-7e4a-4409-9701-ba8be283dbc3"}, s.SecurityGroups) } func TestUpdatePropagateUplinkStatus(t *testing.T) { @@ -692,9 +692,9 @@ func TestUpdatePortSecurity(t *testing.T) { err := ports.Update(context.TODO(), fake.ServiceClient(fakeServer), "65c0ee9f-d634-4522-8954-51021b570b0d", updateOpts).ExtractInto(&portWithExt) th.AssertNoErr(t, err) - th.AssertEquals(t, portWithExt.Status, "DOWN") - th.AssertEquals(t, portWithExt.Name, "private-port") - th.AssertEquals(t, portWithExt.PortSecurityEnabled, false) + th.AssertEquals(t, "DOWN", portWithExt.Status) + th.AssertEquals(t, "private-port", portWithExt.Name) + th.AssertEquals(t, false, portWithExt.PortSecurityEnabled) } func TestUpdateRevision(t *testing.T) { @@ -782,13 +782,13 @@ func TestRemoveSecurityGroups(t *testing.T) { s, err := ports.Update(context.TODO(), fake.ServiceClient(fakeServer), "65c0ee9f-d634-4522-8954-51021b570b0d", options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, s.Name, "new_port_name") - th.AssertDeepEquals(t, s.FixedIPs, []ports.IP{ + th.AssertEquals(t, "new_port_name", s.Name) + th.AssertDeepEquals(t, []ports.IP{ {SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.3"}, - }) - th.AssertDeepEquals(t, s.AllowedAddressPairs, []ports.AddressPair{ + }, s.FixedIPs) + th.AssertDeepEquals(t, []ports.AddressPair{ {IPAddress: "10.0.0.4", MACAddress: "fa:16:3e:c9:cb:f0"}, - }) + }, s.AllowedAddressPairs) th.AssertDeepEquals(t, s.SecurityGroups, []string(nil)) } @@ -822,12 +822,12 @@ func TestRemoveAllowedAddressPairs(t *testing.T) { s, err := ports.Update(context.TODO(), fake.ServiceClient(fakeServer), "65c0ee9f-d634-4522-8954-51021b570b0d", options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, s.Name, "new_port_name") - th.AssertDeepEquals(t, s.FixedIPs, []ports.IP{ + th.AssertEquals(t, "new_port_name", s.Name) + th.AssertDeepEquals(t, []ports.IP{ {SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.3"}, - }) + }, s.FixedIPs) th.AssertDeepEquals(t, s.AllowedAddressPairs, []ports.AddressPair(nil)) - th.AssertDeepEquals(t, s.SecurityGroups, []string{"f0ac4394-7e4a-4409-9701-ba8be283dbc3"}) + th.AssertDeepEquals(t, []string{"f0ac4394-7e4a-4409-9701-ba8be283dbc3"}, s.SecurityGroups) } func TestDontUpdateAllowedAddressPairs(t *testing.T) { @@ -859,14 +859,14 @@ func TestDontUpdateAllowedAddressPairs(t *testing.T) { s, err := ports.Update(context.TODO(), fake.ServiceClient(fakeServer), "65c0ee9f-d634-4522-8954-51021b570b0d", options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, s.Name, "new_port_name") - th.AssertDeepEquals(t, s.FixedIPs, []ports.IP{ + th.AssertEquals(t, "new_port_name", s.Name) + th.AssertDeepEquals(t, []ports.IP{ {SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.3"}, - }) - th.AssertDeepEquals(t, s.AllowedAddressPairs, []ports.AddressPair{ + }, s.FixedIPs) + th.AssertDeepEquals(t, []ports.AddressPair{ {IPAddress: "10.0.0.4", MACAddress: "fa:16:3e:c9:cb:f0"}, - }) - th.AssertDeepEquals(t, s.SecurityGroups, []string{"f0ac4394-7e4a-4409-9701-ba8be283dbc3"}) + }, s.AllowedAddressPairs) + th.AssertDeepEquals(t, []string{"f0ac4394-7e4a-4409-9701-ba8be283dbc3"}, s.SecurityGroups) } func TestDelete(t *testing.T) { @@ -905,25 +905,25 @@ func TestGetWithExtraDHCPOpts(t *testing.T) { err := ports.Get(context.TODO(), fake.ServiceClient(fakeServer), "46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2").ExtractInto(&s) th.AssertNoErr(t, err) - th.AssertEquals(t, s.Status, "ACTIVE") - th.AssertEquals(t, s.NetworkID, "a87cc70a-3e15-4acf-8205-9b711a3531b7") - th.AssertEquals(t, s.TenantID, "d6700c0c9ffa4f1cb322cd4a1f3906fa") - th.AssertEquals(t, s.AdminStateUp, true) - th.AssertEquals(t, s.Name, "port-with-extra-dhcp-opts") - th.AssertEquals(t, s.DeviceOwner, "") - th.AssertEquals(t, s.MACAddress, "fa:16:3e:c9:cb:f0") - th.AssertDeepEquals(t, s.FixedIPs, []ports.IP{ + th.AssertEquals(t, "ACTIVE", s.Status) + th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", s.NetworkID) + th.AssertEquals(t, "d6700c0c9ffa4f1cb322cd4a1f3906fa", s.TenantID) + th.AssertEquals(t, true, s.AdminStateUp) + th.AssertEquals(t, "port-with-extra-dhcp-opts", s.Name) + th.AssertEquals(t, "", s.DeviceOwner) + th.AssertEquals(t, "fa:16:3e:c9:cb:f0", s.MACAddress) + th.AssertDeepEquals(t, []ports.IP{ {SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.4"}, - }) - th.AssertEquals(t, s.ID, "65c0ee9f-d634-4522-8954-51021b570b0d") - th.AssertEquals(t, s.DeviceID, "") - - th.AssertDeepEquals(t, s.ExtraDHCPOpts[0].OptName, "option1") - th.AssertDeepEquals(t, s.ExtraDHCPOpts[0].OptValue, "value1") - th.AssertDeepEquals(t, s.ExtraDHCPOpts[0].IPVersion, 4) - th.AssertDeepEquals(t, s.ExtraDHCPOpts[1].OptName, "option2") - th.AssertDeepEquals(t, s.ExtraDHCPOpts[1].OptValue, "value2") - th.AssertDeepEquals(t, s.ExtraDHCPOpts[1].IPVersion, 4) + }, s.FixedIPs) + th.AssertEquals(t, "65c0ee9f-d634-4522-8954-51021b570b0d", s.ID) + th.AssertEquals(t, "", s.DeviceID) + + th.AssertDeepEquals(t, "option1", s.ExtraDHCPOpts[0].OptName) + th.AssertDeepEquals(t, "value1", s.ExtraDHCPOpts[0].OptValue) + th.AssertDeepEquals(t, 4, s.ExtraDHCPOpts[0].IPVersion) + th.AssertDeepEquals(t, "option2", s.ExtraDHCPOpts[1].OptName) + th.AssertDeepEquals(t, "value2", s.ExtraDHCPOpts[1].OptValue) + th.AssertDeepEquals(t, 4, s.ExtraDHCPOpts[1].IPVersion) } func TestCreateWithExtraDHCPOpts(t *testing.T) { @@ -971,22 +971,22 @@ func TestCreateWithExtraDHCPOpts(t *testing.T) { err := ports.Create(context.TODO(), fake.ServiceClient(fakeServer), createOpts).ExtractInto(&s) th.AssertNoErr(t, err) - th.AssertEquals(t, s.Status, "DOWN") - th.AssertEquals(t, s.NetworkID, "a87cc70a-3e15-4acf-8205-9b711a3531b7") - th.AssertEquals(t, s.TenantID, "d6700c0c9ffa4f1cb322cd4a1f3906fa") - th.AssertEquals(t, s.AdminStateUp, true) - th.AssertEquals(t, s.Name, "port-with-extra-dhcp-opts") - th.AssertEquals(t, s.DeviceOwner, "") - th.AssertEquals(t, s.MACAddress, "fa:16:3e:c9:cb:f0") - th.AssertDeepEquals(t, s.FixedIPs, []ports.IP{ + th.AssertEquals(t, "DOWN", s.Status) + th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", s.NetworkID) + th.AssertEquals(t, "d6700c0c9ffa4f1cb322cd4a1f3906fa", s.TenantID) + th.AssertEquals(t, true, s.AdminStateUp) + th.AssertEquals(t, "port-with-extra-dhcp-opts", s.Name) + th.AssertEquals(t, "", s.DeviceOwner) + th.AssertEquals(t, "fa:16:3e:c9:cb:f0", s.MACAddress) + th.AssertDeepEquals(t, []ports.IP{ {SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.2"}, - }) - th.AssertEquals(t, s.ID, "65c0ee9f-d634-4522-8954-51021b570b0d") - th.AssertEquals(t, s.DeviceID, "") + }, s.FixedIPs) + th.AssertEquals(t, "65c0ee9f-d634-4522-8954-51021b570b0d", s.ID) + th.AssertEquals(t, "", s.DeviceID) - th.AssertDeepEquals(t, s.ExtraDHCPOpts[0].OptName, "option1") - th.AssertDeepEquals(t, s.ExtraDHCPOpts[0].OptValue, "value1") - th.AssertDeepEquals(t, s.ExtraDHCPOpts[0].IPVersion, 4) + th.AssertDeepEquals(t, "option1", s.ExtraDHCPOpts[0].OptName) + th.AssertDeepEquals(t, "value1", s.ExtraDHCPOpts[0].OptValue) + th.AssertDeepEquals(t, 4, s.ExtraDHCPOpts[0].IPVersion) } func TestUpdateWithExtraDHCPOpts(t *testing.T) { @@ -1036,22 +1036,22 @@ func TestUpdateWithExtraDHCPOpts(t *testing.T) { err := ports.Update(context.TODO(), fake.ServiceClient(fakeServer), "65c0ee9f-d634-4522-8954-51021b570b0d", updateOpts).ExtractInto(&s) th.AssertNoErr(t, err) - th.AssertEquals(t, s.Status, "DOWN") - th.AssertEquals(t, s.NetworkID, "a87cc70a-3e15-4acf-8205-9b711a3531b7") - th.AssertEquals(t, s.TenantID, "d6700c0c9ffa4f1cb322cd4a1f3906fa") - th.AssertEquals(t, s.AdminStateUp, true) - th.AssertEquals(t, s.Name, "updated-port-with-dhcp-opts") - th.AssertEquals(t, s.DeviceOwner, "") - th.AssertEquals(t, s.MACAddress, "fa:16:3e:c9:cb:f0") - th.AssertDeepEquals(t, s.FixedIPs, []ports.IP{ + th.AssertEquals(t, "DOWN", s.Status) + th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", s.NetworkID) + th.AssertEquals(t, "d6700c0c9ffa4f1cb322cd4a1f3906fa", s.TenantID) + th.AssertEquals(t, true, s.AdminStateUp) + th.AssertEquals(t, "updated-port-with-dhcp-opts", s.Name) + th.AssertEquals(t, "", s.DeviceOwner) + th.AssertEquals(t, "fa:16:3e:c9:cb:f0", s.MACAddress) + th.AssertDeepEquals(t, []ports.IP{ {SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.3"}, - }) - th.AssertEquals(t, s.ID, "65c0ee9f-d634-4522-8954-51021b570b0d") - th.AssertEquals(t, s.DeviceID, "") + }, s.FixedIPs) + th.AssertEquals(t, "65c0ee9f-d634-4522-8954-51021b570b0d", s.ID) + th.AssertEquals(t, "", s.DeviceID) - th.AssertDeepEquals(t, s.ExtraDHCPOpts[0].OptName, "option2") - th.AssertDeepEquals(t, s.ExtraDHCPOpts[0].OptValue, "value2") - th.AssertDeepEquals(t, s.ExtraDHCPOpts[0].IPVersion, 4) + th.AssertDeepEquals(t, "option2", s.ExtraDHCPOpts[0].OptName) + th.AssertDeepEquals(t, "value2", s.ExtraDHCPOpts[0].OptValue) + th.AssertDeepEquals(t, 4, s.ExtraDHCPOpts[0].IPVersion) } func TestPortsListOpts(t *testing.T) { diff --git a/openstack/networking/v2/subnets/testing/requests_test.go b/openstack/networking/v2/subnets/testing/requests_test.go index fd8c810db3..5e22f55848 100644 --- a/openstack/networking/v2/subnets/testing/requests_test.go +++ b/openstack/networking/v2/subnets/testing/requests_test.go @@ -71,23 +71,23 @@ func TestGet(t *testing.T) { s, err := subnets.Get(context.TODO(), fake.ServiceClient(fakeServer), "54d6f61d-db07-451c-9ab3-b9609b6b6f0b").Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, s.Name, "my_subnet") - th.AssertEquals(t, s.EnableDHCP, true) - th.AssertEquals(t, s.NetworkID, "d32019d3-bc6e-4319-9c1d-6722fc136a22") - th.AssertEquals(t, s.TenantID, "4fd44f30292945e481c7b8a0c8908869") - th.AssertDeepEquals(t, s.DNSNameservers, []string{}) - th.AssertDeepEquals(t, s.AllocationPools, []subnets.AllocationPool{ + th.AssertEquals(t, "my_subnet", s.Name) + th.AssertEquals(t, true, s.EnableDHCP) + th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", s.NetworkID) + th.AssertEquals(t, "4fd44f30292945e481c7b8a0c8908869", s.TenantID) + th.AssertDeepEquals(t, []string{}, s.DNSNameservers) + th.AssertDeepEquals(t, []subnets.AllocationPool{ { Start: "192.0.0.2", End: "192.255.255.254", }, - }) - th.AssertDeepEquals(t, s.HostRoutes, []subnets.HostRoute{}) - th.AssertEquals(t, s.IPVersion, 4) - th.AssertEquals(t, s.GatewayIP, "192.0.0.1") - th.AssertEquals(t, s.CIDR, "192.0.0.0/8") - th.AssertEquals(t, s.ID, "54d6f61d-db07-451c-9ab3-b9609b6b6f0b") - th.AssertEquals(t, s.SubnetPoolID, "b80340c7-9960-4f67-a99c-02501656284b") + }, s.AllocationPools) + th.AssertDeepEquals(t, []subnets.HostRoute{}, s.HostRoutes) + th.AssertEquals(t, 4, s.IPVersion) + th.AssertEquals(t, "192.0.0.1", s.GatewayIP) + th.AssertEquals(t, "192.0.0.0/8", s.CIDR) + th.AssertEquals(t, "54d6f61d-db07-451c-9ab3-b9609b6b6f0b", s.ID) + th.AssertEquals(t, "b80340c7-9960-4f67-a99c-02501656284b", s.SubnetPoolID) } func TestCreate(t *testing.T) { @@ -131,25 +131,25 @@ func TestCreate(t *testing.T) { s, err := subnets.Create(context.TODO(), fake.ServiceClient(fakeServer), opts).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, s.Name, "") - th.AssertEquals(t, s.DNSPublishFixedIP, true) - th.AssertEquals(t, s.EnableDHCP, true) - th.AssertEquals(t, s.NetworkID, "d32019d3-bc6e-4319-9c1d-6722fc136a22") - th.AssertEquals(t, s.TenantID, "4fd44f30292945e481c7b8a0c8908869") - th.AssertDeepEquals(t, s.DNSNameservers, []string{"foo"}) - th.AssertDeepEquals(t, s.ServiceTypes, []string{"network:routed"}) - th.AssertDeepEquals(t, s.AllocationPools, []subnets.AllocationPool{ + th.AssertEquals(t, "", s.Name) + th.AssertEquals(t, true, s.DNSPublishFixedIP) + th.AssertEquals(t, true, s.EnableDHCP) + th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", s.NetworkID) + th.AssertEquals(t, "4fd44f30292945e481c7b8a0c8908869", s.TenantID) + th.AssertDeepEquals(t, []string{"foo"}, s.DNSNameservers) + th.AssertDeepEquals(t, []string{"network:routed"}, s.ServiceTypes) + th.AssertDeepEquals(t, []subnets.AllocationPool{ { Start: "192.168.199.2", End: "192.168.199.254", }, - }) - th.AssertDeepEquals(t, s.HostRoutes, []subnets.HostRoute{}) - th.AssertEquals(t, s.IPVersion, 4) - th.AssertEquals(t, s.GatewayIP, "192.168.199.1") - th.AssertEquals(t, s.CIDR, "192.168.199.0/24") - th.AssertEquals(t, s.ID, "3b80198d-4f7b-4f77-9ef5-774d54e17126") - th.AssertEquals(t, s.SubnetPoolID, "b80340c7-9960-4f67-a99c-02501656284b") + }, s.AllocationPools) + th.AssertDeepEquals(t, []subnets.HostRoute{}, s.HostRoutes) + th.AssertEquals(t, 4, s.IPVersion) + th.AssertEquals(t, "192.168.199.1", s.GatewayIP) + th.AssertEquals(t, "192.168.199.0/24", s.CIDR) + th.AssertEquals(t, "3b80198d-4f7b-4f77-9ef5-774d54e17126", s.ID) + th.AssertEquals(t, "b80340c7-9960-4f67-a99c-02501656284b", s.SubnetPoolID) } func TestCreateNoGateway(t *testing.T) { @@ -186,21 +186,21 @@ func TestCreateNoGateway(t *testing.T) { s, err := subnets.Create(context.TODO(), fake.ServiceClient(fakeServer), opts).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, s.Name, "") - th.AssertEquals(t, s.EnableDHCP, true) - th.AssertEquals(t, s.NetworkID, "d32019d3-bc6e-4319-9c1d-6722fc136a23") - th.AssertEquals(t, s.TenantID, "4fd44f30292945e481c7b8a0c8908869") - th.AssertDeepEquals(t, s.AllocationPools, []subnets.AllocationPool{ + th.AssertEquals(t, "", s.Name) + th.AssertEquals(t, true, s.EnableDHCP) + th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a23", s.NetworkID) + th.AssertEquals(t, "4fd44f30292945e481c7b8a0c8908869", s.TenantID) + th.AssertDeepEquals(t, []subnets.AllocationPool{ { Start: "192.168.1.2", End: "192.168.1.254", }, - }) - th.AssertDeepEquals(t, s.HostRoutes, []subnets.HostRoute{}) - th.AssertEquals(t, s.IPVersion, 4) - th.AssertEquals(t, s.GatewayIP, "") - th.AssertEquals(t, s.CIDR, "192.168.1.0/24") - th.AssertEquals(t, s.ID, "54d6f61d-db07-451c-9ab3-b9609b6b6f0c") + }, s.AllocationPools) + th.AssertDeepEquals(t, []subnets.HostRoute{}, s.HostRoutes) + th.AssertEquals(t, 4, s.IPVersion) + th.AssertEquals(t, "", s.GatewayIP) + th.AssertEquals(t, "192.168.1.0/24", s.CIDR) + th.AssertEquals(t, "54d6f61d-db07-451c-9ab3-b9609b6b6f0c", s.ID) } func TestCreateDefaultGateway(t *testing.T) { @@ -235,21 +235,21 @@ func TestCreateDefaultGateway(t *testing.T) { s, err := subnets.Create(context.TODO(), fake.ServiceClient(fakeServer), opts).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, s.Name, "") - th.AssertEquals(t, s.EnableDHCP, true) - th.AssertEquals(t, s.NetworkID, "d32019d3-bc6e-4319-9c1d-6722fc136a23") - th.AssertEquals(t, s.TenantID, "4fd44f30292945e481c7b8a0c8908869") - th.AssertDeepEquals(t, s.AllocationPools, []subnets.AllocationPool{ + th.AssertEquals(t, "", s.Name) + th.AssertEquals(t, true, s.EnableDHCP) + th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a23", s.NetworkID) + th.AssertEquals(t, "4fd44f30292945e481c7b8a0c8908869", s.TenantID) + th.AssertDeepEquals(t, []subnets.AllocationPool{ { Start: "192.168.1.2", End: "192.168.1.254", }, - }) - th.AssertDeepEquals(t, s.HostRoutes, []subnets.HostRoute{}) - th.AssertEquals(t, s.IPVersion, 4) - th.AssertEquals(t, s.GatewayIP, "192.168.1.1") - th.AssertEquals(t, s.CIDR, "192.168.1.0/24") - th.AssertEquals(t, s.ID, "54d6f61d-db07-451c-9ab3-b9609b6b6f0c") + }, s.AllocationPools) + th.AssertDeepEquals(t, []subnets.HostRoute{}, s.HostRoutes) + th.AssertEquals(t, 4, s.IPVersion) + th.AssertEquals(t, "192.168.1.1", s.GatewayIP) + th.AssertEquals(t, "192.168.1.0/24", s.CIDR) + th.AssertEquals(t, "54d6f61d-db07-451c-9ab3-b9609b6b6f0c", s.ID) } func TestCreateIPv6RaAddressMode(t *testing.T) { @@ -281,16 +281,16 @@ func TestCreateIPv6RaAddressMode(t *testing.T) { s, err := subnets.Create(context.TODO(), fake.ServiceClient(fakeServer), opts).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, s.Name, "") - th.AssertEquals(t, s.EnableDHCP, true) - th.AssertEquals(t, s.NetworkID, "d32019d3-bc6e-4319-9c1d-6722fc136a22") - th.AssertEquals(t, s.TenantID, "4fd44f30292945e481c7b8a0c8908869") - th.AssertEquals(t, s.IPVersion, 6) - th.AssertEquals(t, s.GatewayIP, "2001:db8:0:a::1") - th.AssertEquals(t, s.CIDR, "2001:db8:0:a:0:0:0:0/64") - th.AssertEquals(t, s.ID, "3b80198d-4f7b-4f77-9ef5-774d54e17126") - th.AssertEquals(t, s.IPv6AddressMode, "slaac") - th.AssertEquals(t, s.IPv6RAMode, "slaac") + th.AssertEquals(t, "", s.Name) + th.AssertEquals(t, true, s.EnableDHCP) + th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", s.NetworkID) + th.AssertEquals(t, "4fd44f30292945e481c7b8a0c8908869", s.TenantID) + th.AssertEquals(t, 6, s.IPVersion) + th.AssertEquals(t, "2001:db8:0:a::1", s.GatewayIP) + th.AssertEquals(t, "2001:db8:0:a:0:0:0:0/64", s.CIDR) + th.AssertEquals(t, "3b80198d-4f7b-4f77-9ef5-774d54e17126", s.ID) + th.AssertEquals(t, "slaac", s.IPv6AddressMode) + th.AssertEquals(t, "slaac", s.IPv6RAMode) } func TestCreateWithNoCIDR(t *testing.T) { @@ -322,24 +322,24 @@ func TestCreateWithNoCIDR(t *testing.T) { s, err := subnets.Create(context.TODO(), fake.ServiceClient(fakeServer), opts).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, s.Name, "") - th.AssertEquals(t, s.DNSPublishFixedIP, true) - th.AssertEquals(t, s.EnableDHCP, true) - th.AssertEquals(t, s.NetworkID, "d32019d3-bc6e-4319-9c1d-6722fc136a22") - th.AssertEquals(t, s.TenantID, "4fd44f30292945e481c7b8a0c8908869") - th.AssertDeepEquals(t, s.DNSNameservers, []string{"foo"}) - th.AssertDeepEquals(t, s.AllocationPools, []subnets.AllocationPool{ + th.AssertEquals(t, "", s.Name) + th.AssertEquals(t, true, s.DNSPublishFixedIP) + th.AssertEquals(t, true, s.EnableDHCP) + th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", s.NetworkID) + th.AssertEquals(t, "4fd44f30292945e481c7b8a0c8908869", s.TenantID) + th.AssertDeepEquals(t, []string{"foo"}, s.DNSNameservers) + th.AssertDeepEquals(t, []subnets.AllocationPool{ { Start: "192.168.199.2", End: "192.168.199.254", }, - }) - th.AssertDeepEquals(t, s.HostRoutes, []subnets.HostRoute{}) - th.AssertEquals(t, s.IPVersion, 4) - th.AssertEquals(t, s.GatewayIP, "192.168.199.1") - th.AssertEquals(t, s.CIDR, "192.168.199.0/24") - th.AssertEquals(t, s.ID, "3b80198d-4f7b-4f77-9ef5-774d54e17126") - th.AssertEquals(t, s.SubnetPoolID, "b80340c7-9960-4f67-a99c-02501656284b") + }, s.AllocationPools) + th.AssertDeepEquals(t, []subnets.HostRoute{}, s.HostRoutes) + th.AssertEquals(t, 4, s.IPVersion) + th.AssertEquals(t, "192.168.199.1", s.GatewayIP) + th.AssertEquals(t, "192.168.199.0/24", s.CIDR) + th.AssertEquals(t, "3b80198d-4f7b-4f77-9ef5-774d54e17126", s.ID) + th.AssertEquals(t, "b80340c7-9960-4f67-a99c-02501656284b", s.SubnetPoolID) } func TestCreateWithPrefixlen(t *testing.T) { @@ -372,24 +372,24 @@ func TestCreateWithPrefixlen(t *testing.T) { s, err := subnets.Create(context.TODO(), fake.ServiceClient(fakeServer), opts).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, s.Name, "") - th.AssertEquals(t, s.DNSPublishFixedIP, true) - th.AssertEquals(t, s.EnableDHCP, true) - th.AssertEquals(t, s.NetworkID, "d32019d3-bc6e-4319-9c1d-6722fc136a22") - th.AssertEquals(t, s.TenantID, "4fd44f30292945e481c7b8a0c8908869") - th.AssertDeepEquals(t, s.DNSNameservers, []string{"foo"}) - th.AssertDeepEquals(t, s.AllocationPools, []subnets.AllocationPool{ + th.AssertEquals(t, "", s.Name) + th.AssertEquals(t, true, s.DNSPublishFixedIP) + th.AssertEquals(t, true, s.EnableDHCP) + th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", s.NetworkID) + th.AssertEquals(t, "4fd44f30292945e481c7b8a0c8908869", s.TenantID) + th.AssertDeepEquals(t, []string{"foo"}, s.DNSNameservers) + th.AssertDeepEquals(t, []subnets.AllocationPool{ { Start: "192.168.199.2", End: "192.168.199.254", }, - }) - th.AssertDeepEquals(t, s.HostRoutes, []subnets.HostRoute{}) - th.AssertEquals(t, s.IPVersion, 4) - th.AssertEquals(t, s.GatewayIP, "192.168.199.1") - th.AssertEquals(t, s.CIDR, "192.168.199.0/24") - th.AssertEquals(t, s.ID, "3b80198d-4f7b-4f77-9ef5-774d54e17126") - th.AssertEquals(t, s.SubnetPoolID, "b80340c7-9960-4f67-a99c-02501656284b") + }, s.AllocationPools) + th.AssertDeepEquals(t, []subnets.HostRoute{}, s.HostRoutes) + th.AssertEquals(t, 4, s.IPVersion) + th.AssertEquals(t, "192.168.199.1", s.GatewayIP) + th.AssertEquals(t, "192.168.199.0/24", s.CIDR) + th.AssertEquals(t, "3b80198d-4f7b-4f77-9ef5-774d54e17126", s.ID) + th.AssertEquals(t, "b80340c7-9960-4f67-a99c-02501656284b", s.SubnetPoolID) } func TestRequiredCreateOpts(t *testing.T) { @@ -441,8 +441,8 @@ func TestUpdate(t *testing.T) { s, err := subnets.Update(context.TODO(), fake.ServiceClient(fakeServer), "08eae331-0402-425a-923c-34f7cfe39c1b", opts).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, s.Name, "my_new_subnet") - th.AssertEquals(t, s.ID, "08eae331-0402-425a-923c-34f7cfe39c1b") + th.AssertEquals(t, "my_new_subnet", s.Name) + th.AssertEquals(t, "08eae331-0402-425a-923c-34f7cfe39c1b", s.ID) } func TestUpdateGateway(t *testing.T) { @@ -471,9 +471,9 @@ func TestUpdateGateway(t *testing.T) { s, err := subnets.Update(context.TODO(), fake.ServiceClient(fakeServer), "08eae331-0402-425a-923c-34f7cfe39c1b", opts).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, s.Name, "my_new_subnet") - th.AssertEquals(t, s.ID, "08eae331-0402-425a-923c-34f7cfe39c1b") - th.AssertEquals(t, s.GatewayIP, "10.0.0.1") + th.AssertEquals(t, "my_new_subnet", s.Name) + th.AssertEquals(t, "08eae331-0402-425a-923c-34f7cfe39c1b", s.ID) + th.AssertEquals(t, "10.0.0.1", s.GatewayIP) } func TestUpdateRemoveGateway(t *testing.T) { @@ -502,9 +502,9 @@ func TestUpdateRemoveGateway(t *testing.T) { s, err := subnets.Update(context.TODO(), fake.ServiceClient(fakeServer), "08eae331-0402-425a-923c-34f7cfe39c1b", opts).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, s.Name, "my_new_subnet") - th.AssertEquals(t, s.ID, "08eae331-0402-425a-923c-34f7cfe39c1b") - th.AssertEquals(t, s.GatewayIP, "") + th.AssertEquals(t, "my_new_subnet", s.Name) + th.AssertEquals(t, "08eae331-0402-425a-923c-34f7cfe39c1b", s.ID) + th.AssertEquals(t, "", s.GatewayIP) } func TestUpdateHostRoutes(t *testing.T) { @@ -539,8 +539,8 @@ func TestUpdateHostRoutes(t *testing.T) { s, err := subnets.Update(context.TODO(), fake.ServiceClient(fakeServer), "08eae331-0402-425a-923c-34f7cfe39c1b", opts).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, s.Name, "my_new_subnet") - th.AssertEquals(t, s.ID, "08eae331-0402-425a-923c-34f7cfe39c1b") + th.AssertEquals(t, "my_new_subnet", s.Name) + th.AssertEquals(t, "08eae331-0402-425a-923c-34f7cfe39c1b", s.ID) th.AssertDeepEquals(t, s.HostRoutes, HostRoutes) } @@ -568,8 +568,8 @@ func TestUpdateRemoveHostRoutes(t *testing.T) { s, err := subnets.Update(context.TODO(), fake.ServiceClient(fakeServer), "08eae331-0402-425a-923c-34f7cfe39c1b", opts).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, s.Name, "my_new_subnet") - th.AssertEquals(t, s.ID, "08eae331-0402-425a-923c-34f7cfe39c1b") + th.AssertEquals(t, "my_new_subnet", s.Name) + th.AssertEquals(t, "08eae331-0402-425a-923c-34f7cfe39c1b", s.ID) th.AssertDeepEquals(t, s.HostRoutes, noHostRoutes) } @@ -603,14 +603,14 @@ func TestUpdateAllocationPool(t *testing.T) { s, err := subnets.Update(context.TODO(), fake.ServiceClient(fakeServer), "08eae331-0402-425a-923c-34f7cfe39c1b", opts).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, s.Name, "my_new_subnet") - th.AssertEquals(t, s.ID, "08eae331-0402-425a-923c-34f7cfe39c1b") - th.AssertDeepEquals(t, s.AllocationPools, []subnets.AllocationPool{ + th.AssertEquals(t, "my_new_subnet", s.Name) + th.AssertEquals(t, "08eae331-0402-425a-923c-34f7cfe39c1b", s.ID) + th.AssertDeepEquals(t, []subnets.AllocationPool{ { Start: "10.1.0.2", End: "10.1.0.254", }, - }) + }, s.AllocationPools) } func TestUpdateRevision(t *testing.T) { diff --git a/openstack/networking/v2/subnets/testing/results_test.go b/openstack/networking/v2/subnets/testing/results_test.go index 273607bb51..0cef30bc36 100644 --- a/openstack/networking/v2/subnets/testing/results_test.go +++ b/openstack/networking/v2/subnets/testing/results_test.go @@ -54,6 +54,6 @@ func TestHostRoute(t *testing.T) { t.Fatalf("%s", err) } route := subnetWrapper.Subnet.HostRoutes[0] - th.AssertEquals(t, route.NextHop, "172.16.0.2") - th.AssertEquals(t, route.DestinationCIDR, "172.20.1.0/24") + th.AssertEquals(t, "172.16.0.2", route.NextHop) + th.AssertEquals(t, "172.20.1.0/24", route.DestinationCIDR) } diff --git a/openstack/objectstorage/v1/objects/testing/requests_test.go b/openstack/objectstorage/v1/objects/testing/requests_test.go index b49cf63a7f..9e8766415c 100644 --- a/openstack/objectstorage/v1/objects/testing/requests_test.go +++ b/openstack/objectstorage/v1/objects/testing/requests_test.go @@ -490,7 +490,7 @@ func TestObjectCreateParamsWithSeek(t *testing.T) { th.AssertNoErr(t, err) _, ok := reader.(io.ReadSeeker) - th.AssertEquals(t, ok, true) + th.AssertEquals(t, true, ok) c, err := io.ReadAll(reader) th.AssertNoErr(t, err) diff --git a/openstack/orchestration/v1/stackevents/testing/requests_test.go b/openstack/orchestration/v1/stackevents/testing/requests_test.go index d1c60abf3a..f378916881 100644 --- a/openstack/orchestration/v1/stackevents/testing/requests_test.go +++ b/openstack/orchestration/v1/stackevents/testing/requests_test.go @@ -38,7 +38,7 @@ func TestList(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestListResourceEvents(t *testing.T) { @@ -57,7 +57,7 @@ func TestListResourceEvents(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestGetEvent(t *testing.T) { diff --git a/openstack/orchestration/v1/stackresources/testing/requests_test.go b/openstack/orchestration/v1/stackresources/testing/requests_test.go index 2852716bd8..4f0afa8ccf 100644 --- a/openstack/orchestration/v1/stackresources/testing/requests_test.go +++ b/openstack/orchestration/v1/stackresources/testing/requests_test.go @@ -39,7 +39,7 @@ func TestListResources(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestGetResource(t *testing.T) { diff --git a/openstack/orchestration/v1/stacks/testing/requests_test.go b/openstack/orchestration/v1/stacks/testing/requests_test.go index 6c373315ec..75a4f3d47c 100644 --- a/openstack/orchestration/v1/stacks/testing/requests_test.go +++ b/openstack/orchestration/v1/stacks/testing/requests_test.go @@ -125,7 +125,7 @@ func TestListStack(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestGetStack(t *testing.T) { diff --git a/openstack/orchestration/v1/stacks/utils_test.go b/openstack/orchestration/v1/stacks/utils_test.go index 1daceefa93..22b36ba19a 100644 --- a/openstack/orchestration/v1/stacks/utils_test.go +++ b/openstack/orchestration/v1/stacks/utils_test.go @@ -23,7 +23,7 @@ func TestGetHTTPClient(t *testing.T) { th.AssertNoErr(t, err) resp, err := client.Get(baseurl) th.AssertNoErr(t, err) - th.AssertEquals(t, resp.StatusCode, 200) + th.AssertEquals(t, 200, resp.StatusCode) } // Implement a fakeclient that can be used to mock out HTTP requests diff --git a/openstack/sharedfilesystems/apiversions/testing/requests_test.go b/openstack/sharedfilesystems/apiversions/testing/requests_test.go index ab2d2a184f..e2ea355901 100644 --- a/openstack/sharedfilesystems/apiversions/testing/requests_test.go +++ b/openstack/sharedfilesystems/apiversions/testing/requests_test.go @@ -43,7 +43,7 @@ func TestGetNoAPIVersion(t *testing.T) { MockGetNoResponse(t, fakeServer) _, err := apiversions.Get(context.TODO(), client.ServiceClient(fakeServer), "v2").Extract() - th.AssertEquals(t, err.Error(), "Unable to find requested API version") + th.AssertEquals(t, "Unable to find requested API version", err.Error()) } func TestGetMultipleAPIVersion(t *testing.T) { @@ -53,5 +53,5 @@ func TestGetMultipleAPIVersion(t *testing.T) { MockGetMultipleResponses(t, fakeServer) _, err := apiversions.Get(context.TODO(), client.ServiceClient(fakeServer), "v2").Extract() - th.AssertEquals(t, err.Error(), "Found 2 API versions") + th.AssertEquals(t, "Found 2 API versions", err.Error()) } diff --git a/openstack/sharedfilesystems/v2/errors/testing/request_test.go b/openstack/sharedfilesystems/v2/errors/testing/request_test.go index cc3d987348..035ff50a54 100644 --- a/openstack/sharedfilesystems/v2/errors/testing/request_test.go +++ b/openstack/sharedfilesystems/v2/errors/testing/request_test.go @@ -28,8 +28,8 @@ func TestCreate(t *testing.T) { th.AssertNoErr(t, e) for k, msg := range detailedErr { - th.AssertEquals(t, k, "itemNotFound") - th.AssertEquals(t, msg.Code, 404) - th.AssertEquals(t, msg.Message, "ShareSnapshotNotFound: Snapshot 70bfbebc-d3ff-4528-8bbb-58422daa280b could not be found.") + th.AssertEquals(t, "itemNotFound", k) + th.AssertEquals(t, 404, msg.Code) + th.AssertEquals(t, "ShareSnapshotNotFound: Snapshot 70bfbebc-d3ff-4528-8bbb-58422daa280b could not be found.", msg.Message) } } diff --git a/openstack/sharedfilesystems/v2/replicas/testing/request_test.go b/openstack/sharedfilesystems/v2/replicas/testing/request_test.go index f083ad664d..64c964935e 100644 --- a/openstack/sharedfilesystems/v2/replicas/testing/request_test.go +++ b/openstack/sharedfilesystems/v2/replicas/testing/request_test.go @@ -218,7 +218,7 @@ func TestGetExportLocationSuccess(t *testing.T) { s, err := replicas.GetExportLocation(context.TODO(), getClient(fakeServer, "2.47"), replicaID, "ae73e762-e8b9-4aad-aad3-23afb7cd6825").Extract() th.AssertNoErr(t, err) - th.AssertDeepEquals(t, s, &replicas.ExportLocation{ + th.AssertDeepEquals(t, &replicas.ExportLocation{ Path: "192.168.1.124:/var/lib/manila/mnt/share-3b9c33e8-b136-45c6-84a6-019c8db1d550", ID: "ae73e762-e8b9-4aad-aad3-23afb7cd6825", Preferred: false, @@ -226,7 +226,7 @@ func TestGetExportLocationSuccess(t *testing.T) { AvailabilityZone: "zone-1", CreatedAt: time.Date(2023, time.May, 26, 12, 44, 33, 987960000, time.UTC), UpdatedAt: time.Date(2023, time.May, 26, 12, 44, 33, 958363000, time.UTC), - }) + }, s) } func TestResetStatusSuccess(t *testing.T) { diff --git a/openstack/sharedfilesystems/v2/securityservices/testing/requests_test.go b/openstack/sharedfilesystems/v2/securityservices/testing/requests_test.go index 39232ad7ae..c188258b80 100644 --- a/openstack/sharedfilesystems/v2/securityservices/testing/requests_test.go +++ b/openstack/sharedfilesystems/v2/securityservices/testing/requests_test.go @@ -30,12 +30,12 @@ func TestCreate(t *testing.T) { s, err := securityservices.Create(context.TODO(), client.ServiceClient(fakeServer), options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, s.Name, "SecServ1") - th.AssertEquals(t, s.Description, "Creating my first Security Service") - th.AssertEquals(t, s.User, "demo") - th.AssertEquals(t, s.DNSIP, "10.0.0.0/24") - th.AssertEquals(t, s.Password, "supersecret") - th.AssertEquals(t, s.Type, "kerberos") + th.AssertEquals(t, "SecServ1", s.Name) + th.AssertEquals(t, "Creating my first Security Service", s.Description) + th.AssertEquals(t, "demo", s.User) + th.AssertEquals(t, "10.0.0.0/24", s.DNSIP) + th.AssertEquals(t, "supersecret", s.Password) + th.AssertEquals(t, "kerberos", s.Type) } // Verifies that a security service cannot be created without a type diff --git a/openstack/sharedfilesystems/v2/sharenetworks/testing/requests_test.go b/openstack/sharedfilesystems/v2/sharenetworks/testing/requests_test.go index 5ad5bae072..67210f85eb 100644 --- a/openstack/sharedfilesystems/v2/sharenetworks/testing/requests_test.go +++ b/openstack/sharedfilesystems/v2/sharenetworks/testing/requests_test.go @@ -28,10 +28,10 @@ func TestCreate(t *testing.T) { n, err := sharenetworks.Create(context.TODO(), client.ServiceClient(fakeServer), options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.Name, "my_network") - th.AssertEquals(t, n.Description, "This is my share network") - th.AssertEquals(t, n.NeutronNetID, "998b42ee-2cee-4d36-8b95-67b5ca1f2109") - th.AssertEquals(t, n.NeutronSubnetID, "53482b62-2c84-4a53-b6ab-30d9d9800d06") + th.AssertEquals(t, "my_network", n.Name) + th.AssertEquals(t, "This is my share network", n.Description) + th.AssertEquals(t, "998b42ee-2cee-4d36-8b95-67b5ca1f2109", n.NeutronNetID) + th.AssertEquals(t, "53482b62-2c84-4a53-b6ab-30d9d9800d06", n.NeutronSubnetID) } // Verifies that share network deletion works @@ -136,7 +136,7 @@ func TestPaginatedListDetail(t *testing.T) { }) th.AssertNoErr(t, err) - th.AssertEquals(t, count, 3) + th.AssertEquals(t, 3, count) } // Verifies that it is possible to get a share network diff --git a/openstack/sharedfilesystems/v2/shares/testing/request_test.go b/openstack/sharedfilesystems/v2/shares/testing/request_test.go index 809a39316b..64212ebbb3 100644 --- a/openstack/sharedfilesystems/v2/shares/testing/request_test.go +++ b/openstack/sharedfilesystems/v2/shares/testing/request_test.go @@ -28,11 +28,11 @@ func TestCreate(t *testing.T) { n, err := shares.Create(context.TODO(), client.ServiceClient(fakeServer), options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.Name, "my_test_share") - th.AssertEquals(t, n.Size, 1) - th.AssertEquals(t, n.ShareProto, "NFS") - th.AssertEquals(t, n.Metadata["__affinity_same_host"], "e268f4aa-d571-43dd-9ab3-f49ad06ffaef") - th.AssertEquals(t, n.Metadata["__affinity_different_host"], "e268f4aa-d571-43dd-9ab3-f49ad06ffaef") + th.AssertEquals(t, "my_test_share", n.Name) + th.AssertEquals(t, 1, n.Size) + th.AssertEquals(t, "NFS", n.ShareProto) + th.AssertEquals(t, "e268f4aa-d571-43dd-9ab3-f49ad06ffaef", n.Metadata["__affinity_same_host"]) + th.AssertEquals(t, "e268f4aa-d571-43dd-9ab3-f49ad06ffaef", n.Metadata["__affinity_different_host"]) } func TestUpdate(t *testing.T) { @@ -52,9 +52,9 @@ func TestUpdate(t *testing.T) { n, err := shares.Update(context.TODO(), client.ServiceClient(fakeServer), shareID, options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.Name, "my_new_test_share") - th.AssertEquals(t, n.Description, "") - th.AssertEquals(t, n.IsPublic, false) + th.AssertEquals(t, "my_new_test_share", n.Name) + th.AssertEquals(t, "", n.Description) + th.AssertEquals(t, false, n.IsPublic) } func TestDelete(t *testing.T) { @@ -75,7 +75,7 @@ func TestGet(t *testing.T) { s, err := shares.Get(context.TODO(), client.ServiceClient(fakeServer), shareID).Extract() th.AssertNoErr(t, err) - th.AssertDeepEquals(t, s, &shares.Share{ + th.AssertDeepEquals(t, &shares.Share{ AvailabilityZone: "nova", ShareNetworkID: "713df749-aac0-4a54-af52-10f6c991e80c", ShareServerID: "e268f4aa-d571-43dd-9ab3-f49ad06ffaef", @@ -114,7 +114,7 @@ func TestGet(t *testing.T) { "rel": "bookmark", }, }, - }) + }, s) } func TestListDetail(t *testing.T) { @@ -130,7 +130,7 @@ func TestListDetail(t *testing.T) { actual, err := shares.ExtractShares(allPages) th.AssertNoErr(t, err) - th.AssertDeepEquals(t, actual, []shares.Share{ + th.AssertDeepEquals(t, []shares.Share{ { AvailabilityZone: "nova", ShareNetworkID: "713df749-aac0-4a54-af52-10f6c991e80c", @@ -171,7 +171,7 @@ func TestListDetail(t *testing.T) { }, }, }, - }) + }, actual) } func TestListExportLocationsSuccess(t *testing.T) { @@ -187,7 +187,7 @@ func TestListExportLocationsSuccess(t *testing.T) { s, err := shares.ListExportLocations(context.TODO(), c, shareID).Extract() th.AssertNoErr(t, err) - th.AssertDeepEquals(t, s, []shares.ExportLocation{ + th.AssertDeepEquals(t, []shares.ExportLocation{ { Path: "127.0.0.1:/var/lib/manila/mnt/share-9a922036-ad26-4d27-b955-7a1e285fa74d", ShareInstanceID: "011d21e2-fbc3-4e4a-9993-9ea223f73264", @@ -195,7 +195,7 @@ func TestListExportLocationsSuccess(t *testing.T) { ID: "80ed63fc-83bc-4afc-b881-da4a345ac83d", Preferred: false, }, - }) + }, s) } func TestGetExportLocationSuccess(t *testing.T) { @@ -211,13 +211,13 @@ func TestGetExportLocationSuccess(t *testing.T) { s, err := shares.GetExportLocation(context.TODO(), c, shareID, "80ed63fc-83bc-4afc-b881-da4a345ac83d").Extract() th.AssertNoErr(t, err) - th.AssertDeepEquals(t, s, &shares.ExportLocation{ + th.AssertDeepEquals(t, &shares.ExportLocation{ Path: "127.0.0.1:/var/lib/manila/mnt/share-9a922036-ad26-4d27-b955-7a1e285fa74d", ShareInstanceID: "011d21e2-fbc3-4e4a-9993-9ea223f73264", IsAdminOnly: false, ID: "80ed63fc-83bc-4afc-b881-da4a345ac83d", Preferred: false, - }) + }, s) } func TestGrantAcessSuccess(t *testing.T) { @@ -238,7 +238,7 @@ func TestGrantAcessSuccess(t *testing.T) { s, err := shares.GrantAccess(context.TODO(), c, shareID, grantAccessReq).Extract() th.AssertNoErr(t, err) - th.AssertDeepEquals(t, s, &shares.AccessRight{ + th.AssertDeepEquals(t, &shares.AccessRight{ ShareID: "011d21e2-fbc3-4e4a-9993-9ea223f73264", AccessType: "ip", AccessTo: "0.0.0.0/0", @@ -246,7 +246,7 @@ func TestGrantAcessSuccess(t *testing.T) { AccessLevel: "rw", State: "new", ID: "a2f226a5-cee8-430b-8a03-78a59bd84ee8", - }) + }, s) } func TestRevokeAccessSuccess(t *testing.T) { @@ -278,7 +278,7 @@ func TestListAccessRightsSuccess(t *testing.T) { s, err := shares.ListAccessRights(context.TODO(), c, shareID).Extract() th.AssertNoErr(t, err) - th.AssertDeepEquals(t, s, []shares.AccessRight{ + th.AssertDeepEquals(t, []shares.AccessRight{ { ShareID: "011d21e2-fbc3-4e4a-9993-9ea223f73264", AccessType: "ip", @@ -288,7 +288,7 @@ func TestListAccessRightsSuccess(t *testing.T) { State: "new", ID: "a2f226a5-cee8-430b-8a03-78a59bd84ee8", }, - }) + }, s) } func TestExtendSuccess(t *testing.T) { diff --git a/openstack/sharedfilesystems/v2/sharetransfers/testing/requests_test.go b/openstack/sharedfilesystems/v2/sharetransfers/testing/requests_test.go index 06a81ed9fc..13dc397a62 100644 --- a/openstack/sharedfilesystems/v2/sharetransfers/testing/requests_test.go +++ b/openstack/sharedfilesystems/v2/sharetransfers/testing/requests_test.go @@ -58,7 +58,7 @@ func TestListTransfers(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestListTransfersDetail(t *testing.T) { @@ -81,7 +81,7 @@ func TestListTransfersDetail(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.CheckEquals(t, count, 1) + th.CheckEquals(t, 1, count) } func TestListTransfersAllPages(t *testing.T) { diff --git a/openstack/sharedfilesystems/v2/sharetypes/testing/requests_test.go b/openstack/sharedfilesystems/v2/sharetypes/testing/requests_test.go index 7e1af98caf..f7128635f6 100644 --- a/openstack/sharedfilesystems/v2/sharetypes/testing/requests_test.go +++ b/openstack/sharedfilesystems/v2/sharetypes/testing/requests_test.go @@ -32,8 +32,8 @@ func TestCreate(t *testing.T) { st, err := sharetypes.Create(context.TODO(), client.ServiceClient(fakeServer), options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, st.Name, "my_new_share_type") - th.AssertEquals(t, st.IsPublic, true) + th.AssertEquals(t, "my_new_share_type", st.Name) + th.AssertEquals(t, true, st.IsPublic) } // Verifies that a share type can't be created if the required parameters are missing @@ -134,9 +134,9 @@ func TestGetExtraSpecs(t *testing.T) { st, err := sharetypes.GetExtraSpecs(context.TODO(), client.ServiceClient(fakeServer), "shareTypeID").Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, st["snapshot_support"], "True") - th.AssertEquals(t, st["driver_handles_share_servers"], "True") - th.AssertEquals(t, st["my_custom_extra_spec"], "False") + th.AssertEquals(t, "True", st["snapshot_support"]) + th.AssertEquals(t, "True", st["driver_handles_share_servers"]) + th.AssertEquals(t, "False", st["my_custom_extra_spec"]) } // Verifies that an extra specs can be added to a share type @@ -153,7 +153,7 @@ func TestSetExtraSpecs(t *testing.T) { es, err := sharetypes.SetExtraSpecs(context.TODO(), client.ServiceClient(fakeServer), "shareTypeID", options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, es["my_key"], "my_value") + th.AssertEquals(t, "my_value", es["my_key"]) } // Verifies that an extra specification can be unset for a share type diff --git a/openstack/sharedfilesystems/v2/snapshots/testing/request_test.go b/openstack/sharedfilesystems/v2/snapshots/testing/request_test.go index 29330e177f..14700297e2 100644 --- a/openstack/sharedfilesystems/v2/snapshots/testing/request_test.go +++ b/openstack/sharedfilesystems/v2/snapshots/testing/request_test.go @@ -20,11 +20,11 @@ func TestCreate(t *testing.T) { n, err := snapshots.Create(context.TODO(), client.ServiceClient(fakeServer), options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.Name, "test snapshot") - th.AssertEquals(t, n.Description, "test description") - th.AssertEquals(t, n.ShareProto, "NFS") - th.AssertEquals(t, n.ShareSize, 1) - th.AssertEquals(t, n.Size, 1) + th.AssertEquals(t, "test snapshot", n.Name) + th.AssertEquals(t, "test description", n.Description) + th.AssertEquals(t, "NFS", n.ShareProto) + th.AssertEquals(t, 1, n.ShareSize) + th.AssertEquals(t, 1, n.Size) } func TestUpdate(t *testing.T) { @@ -42,8 +42,8 @@ func TestUpdate(t *testing.T) { n, err := snapshots.Update(context.TODO(), client.ServiceClient(fakeServer), snapshotID, options).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, n.Name, "my_new_test_snapshot") - th.AssertEquals(t, n.Description, "") + th.AssertEquals(t, "my_new_test_snapshot", n.Name) + th.AssertEquals(t, "", n.Description) } func TestDelete(t *testing.T) { @@ -64,7 +64,7 @@ func TestGet(t *testing.T) { s, err := snapshots.Get(context.TODO(), client.ServiceClient(fakeServer), snapshotID).Extract() th.AssertNoErr(t, err) - th.AssertDeepEquals(t, s, &snapshots.Snapshot{ + th.AssertDeepEquals(t, &snapshots.Snapshot{ ID: snapshotID, Name: "new_app_snapshot", Description: "", @@ -85,7 +85,7 @@ func TestGet(t *testing.T) { "rel": "bookmark", }, }, - }) + }, s) } func TestListDetail(t *testing.T) { @@ -101,7 +101,7 @@ func TestListDetail(t *testing.T) { actual, err := snapshots.ExtractSnapshots(allPages) th.AssertNoErr(t, err) - th.AssertDeepEquals(t, actual, []snapshots.Snapshot{ + th.AssertDeepEquals(t, []snapshots.Snapshot{ { ID: snapshotID, Name: "new_app_snapshot", @@ -124,7 +124,7 @@ func TestListDetail(t *testing.T) { }, }, }, - }) + }, actual) } func TestResetStatusSuccess(t *testing.T) { diff --git a/pagination/testing/marker_test.go b/pagination/testing/marker_test.go index a17d8687d3..f46ba9d602 100644 --- a/pagination/testing/marker_test.go +++ b/pagination/testing/marker_test.go @@ -114,7 +114,7 @@ func TestEnumerateMarker(t *testing.T) { return true, nil }) th.AssertNoErr(t, err) - th.AssertEquals(t, callCount, 3) + th.AssertEquals(t, 3, callCount) } func TestAllPagesMarker(t *testing.T) { diff --git a/testing/errors_test.go b/testing/errors_test.go index 21e6b2c2e2..0b0b9f28e1 100644 --- a/testing/errors_test.go +++ b/testing/errors_test.go @@ -19,12 +19,12 @@ func TestErrUnexpectedResponseCode(t *testing.T) { ResponseHeader: nil, } - th.AssertEquals(t, err.GetStatusCode(), 404) - th.AssertEquals(t, gophercloud.ResponseCodeIs(err, http.StatusNotFound), true) - th.AssertEquals(t, gophercloud.ResponseCodeIs(err, http.StatusInternalServerError), false) + th.AssertEquals(t, 404, err.GetStatusCode()) + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) + th.AssertEquals(t, false, gophercloud.ResponseCodeIs(err, http.StatusInternalServerError)) //even if application code wraps our error, ResponseCodeIs() should still work errWrapped := fmt.Errorf("could not frobnicate the foobar: %w", err) - th.AssertEquals(t, gophercloud.ResponseCodeIs(errWrapped, http.StatusNotFound), true) - th.AssertEquals(t, gophercloud.ResponseCodeIs(errWrapped, http.StatusInternalServerError), false) + th.AssertEquals(t, true, gophercloud.ResponseCodeIs(errWrapped, http.StatusNotFound)) + th.AssertEquals(t, false, gophercloud.ResponseCodeIs(errWrapped, http.StatusInternalServerError)) } diff --git a/testing/provider_client_test.go b/testing/provider_client_test.go index 7e9cb7be44..27dda57152 100644 --- a/testing/provider_client_test.go +++ b/testing/provider_client_test.go @@ -210,10 +210,10 @@ func TestReauthEndLoop(t *testing.T) { } wg.Wait() - th.AssertEquals(t, info.reauthAttempts, 6) - th.AssertEquals(t, info.maxReauthReached, true) - th.AssertEquals(t, errAfter > 1, true) - th.AssertEquals(t, errUnable < 20, true) + th.AssertEquals(t, 6, info.reauthAttempts) + th.AssertEquals(t, true, info.maxReauthReached) + th.AssertEquals(t, true, errAfter > 1) + th.AssertEquals(t, true, errUnable < 20) } func TestRequestThatCameDuringReauthWaitsUntilItIsCompleted(t *testing.T) { @@ -569,7 +569,7 @@ func TestRequestRetryError(t *testing.T) { if err == nil { t.Fatal("expecting error, got nil") } - th.AssertEquals(t, retryCounter, uint(0)) + th.AssertEquals(t, uint(0), retryCounter) } func TestRequestRetrySuccess(t *testing.T) { @@ -594,7 +594,7 @@ func TestRequestRetrySuccess(t *testing.T) { if err != nil { t.Fatal(err) } - th.AssertEquals(t, retryCounter, uint(0)) + th.AssertEquals(t, uint(0), retryCounter) } func TestRequestRetryContext(t *testing.T) { diff --git a/testing/service_client_test.go b/testing/service_client_test.go index 6d409d20e3..f0877b977d 100644 --- a/testing/service_client_test.go +++ b/testing/service_client_test.go @@ -31,5 +31,5 @@ func TestMoreHeaders(t *testing.T) { c.ProviderClient = new(gophercloud.ProviderClient) resp, err := c.Get(context.TODO(), fmt.Sprintf("%s/route", fakeServer.Endpoint()), nil, nil) th.AssertNoErr(t, err) - th.AssertEquals(t, resp.Request.Header.Get("custom"), "header") + th.AssertEquals(t, "header", resp.Request.Header.Get("custom")) } From 10330ab1c5f74295123fb2594c94400560325490 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Thu, 28 May 2026 11:57:32 +0200 Subject: [PATCH 408/429] Fix incorrect field assertions in acceptance tests Fix bugs where assertions compared the wrong field or compared a value to itself, silently passing due to empty string values. --- internal/acceptance/openstack/identity/v3/endpoint_test.go | 2 +- .../openstack/networking/v2/extensions/dns/dns_test.go | 4 ++-- .../v2/extensions/portsbinding/portsbinding_test.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/acceptance/openstack/identity/v3/endpoint_test.go b/internal/acceptance/openstack/identity/v3/endpoint_test.go index 0ccbebc37b..01f4ff171b 100644 --- a/internal/acceptance/openstack/identity/v3/endpoint_test.go +++ b/internal/acceptance/openstack/identity/v3/endpoint_test.go @@ -59,7 +59,7 @@ func TestEndpointsGet(t *testing.T) { tools.PrintResource(t, e) - th.AssertEquals(t, e.Name, e.Name) + th.AssertEquals(t, endpoint.Name, e.Name) } func TestEndpointsNavigateCatalog(t *testing.T) { diff --git a/internal/acceptance/openstack/networking/v2/extensions/dns/dns_test.go b/internal/acceptance/openstack/networking/v2/extensions/dns/dns_test.go index fd239f8a40..e9aee0dffb 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/dns/dns_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/dns/dns_test.go @@ -125,7 +125,7 @@ func TestDNSPortCRUDL(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, newPort) - th.AssertEquals(t, newPort.Description, newPortName) + th.AssertEquals(t, newPort.Name, newPortName) th.AssertEquals(t, newPort.Description, newPortDescription) th.AssertEquals(t, newPort.DNSName, newDNSName) @@ -242,7 +242,7 @@ func TestDNSNetwork(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, newNetwork) - th.AssertEquals(t, newNetwork.Description, newNetworkName) + th.AssertEquals(t, newNetwork.Name, newNetworkName) th.AssertEquals(t, newNetwork.Description, newNetworkDescription) th.AssertEquals(t, newNetwork.DNSDomain, newNetworkDNSDomain) diff --git a/internal/acceptance/openstack/networking/v2/extensions/portsbinding/portsbinding_test.go b/internal/acceptance/openstack/networking/v2/extensions/portsbinding/portsbinding_test.go index 025217b710..f1b09494a1 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/portsbinding/portsbinding_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/portsbinding/portsbinding_test.go @@ -70,7 +70,7 @@ func TestPortsbindingCRUD(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, newPort) - th.AssertEquals(t, newPortName, newPort.Description) + th.AssertEquals(t, newPortName, newPort.Name) th.AssertEquals(t, newPortDescription, newPort.Description) th.AssertEquals(t, newHostID, newPort.HostID) th.AssertEquals(t, "normal", newPort.VNICType) From 58430ff8de07343dc150bacba319d9e4c9791b6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Thu, 28 May 2026 15:25:23 +0200 Subject: [PATCH 409/429] testhelper: add new test assertion helpers Add AssertTrue, AssertFalse, CheckTrue, CheckFalse for boolean assertions, and AssertEqualsIgnoreCase, CheckEqualsIgnoreCase for case-insensitive string comparisons. Replace all existing uses of AssertEquals and CheckEquals with boolean literal arguments to use the new helpers instead. --- .../baremetal/httpbasic/allocations_test.go | 2 +- .../baremetal/httpbasic/nodes_test.go | 4 +- .../baremetal/httpbasic/ports_test.go | 2 +- .../baremetal/noauth/allocations_test.go | 2 +- .../openstack/baremetal/noauth/nodes_test.go | 4 +- .../openstack/baremetal/noauth/ports_test.go | 2 +- .../baremetal/v1/allocations_test.go | 2 +- .../openstack/baremetal/v1/nodes_test.go | 8 +-- .../openstack/baremetal/v1/ports_test.go | 2 +- .../openstack/blockstorage/v2/backups_test.go | 2 +- .../blockstorage/v2/snapshots_test.go | 2 +- .../openstack/blockstorage/v2/volumes_test.go | 2 +- .../blockstorage/v2/volumetenants_test.go | 2 +- .../openstack/blockstorage/v3/backups_test.go | 2 +- .../openstack/blockstorage/v3/blockstorage.go | 8 +-- .../blockstorage/v3/manageablevolumes_test.go | 2 +- .../openstack/blockstorage/v3/qos_test.go | 2 +- .../blockstorage/v3/snapshots_test.go | 4 +- .../openstack/blockstorage/v3/volumes_test.go | 4 +- .../blockstorage/v3/volumetenants_test.go | 2 +- .../blockstorage/v3/volumetypes_test.go | 2 +- .../compute/v2/attachinterfaces_test.go | 2 +- .../compute/v2/availabilityzones_test.go | 4 +- .../openstack/compute/v2/compute.go | 4 +- .../openstack/compute/v2/diagnostics_test.go | 2 +- .../openstack/compute/v2/extension_test.go | 2 +- .../openstack/compute/v2/flavors_test.go | 2 +- .../compute/v2/instance_actions_test.go | 4 +- .../openstack/compute/v2/keypairs_test.go | 4 +- .../openstack/compute/v2/secgroup_test.go | 6 +- .../openstack/compute/v2/servergroup_test.go | 4 +- .../openstack/compute/v2/servers_test.go | 26 ++++----- .../openstack/compute/v2/services_test.go | 4 +- .../containerinfra/v1/clusters_test.go | 6 +- .../v1/clustertemplates_test.go | 6 +- .../containerinfra/v1/containerinfra.go | 4 +- .../containerinfra/v1/nodegroups_test.go | 4 +- .../openstack/dns/v2/recordsets_test.go | 4 +- .../openstack/dns/v2/transfers_test.go | 4 +- .../openstack/dns/v2/tsigkeys_test.go | 2 +- .../acceptance/openstack/dns/v2/zones_test.go | 2 +- .../openstack/identity/v2/extension_test.go | 2 +- .../openstack/identity/v2/role_test.go | 4 +- .../openstack/identity/v2/tenant_test.go | 2 +- .../openstack/identity/v2/user_test.go | 2 +- .../v3/applicationcredentials_test.go | 10 ++-- .../openstack/identity/v3/domains_test.go | 2 +- .../openstack/identity/v3/endpoint_test.go | 2 +- .../openstack/identity/v3/federation_test.go | 2 +- .../openstack/identity/v3/groups_test.go | 6 +- .../openstack/identity/v3/oauth1_test.go | 4 +- .../openstack/identity/v3/policies_test.go | 6 +- .../openstack/identity/v3/projects_test.go | 14 ++--- .../openstack/identity/v3/roles_test.go | 24 ++++---- .../openstack/identity/v3/service_test.go | 2 +- .../openstack/identity/v3/trusts_test.go | 2 +- .../openstack/identity/v3/users_test.go | 14 ++--- .../openstack/image/v2/images_test.go | 4 +- .../openstack/keymanager/v1/acls_test.go | 8 +-- .../keymanager/v1/containers_test.go | 4 +- .../openstack/keymanager/v1/orders_test.go | 2 +- .../openstack/keymanager/v1/secrets_test.go | 2 +- .../openstack/loadbalancer/v2/loadbalancer.go | 6 +- .../v2/extensions/attributestags_test.go | 4 +- .../v2/extensions/bgpvpns/bgpvpns_test.go | 4 +- .../v2/extensions/fwaas_v2/groups_test.go | 2 +- .../v2/extensions/fwaas_v2/policy_test.go | 2 +- .../v2/extensions/fwaas_v2/rule_test.go | 2 +- .../extensions/layer3/addressscopes_test.go | 2 +- .../v2/extensions/layer3/floatingips_test.go | 2 +- .../extensions/layer3/l3_scheduling_test.go | 4 +- .../extensions/layer3/portforwardings_test.go | 4 +- .../v2/extensions/layer3/routers_test.go | 4 +- .../extensions/qos/policies/policies_test.go | 2 +- .../v2/extensions/qos/rules/rules_test.go | 6 +- .../networking/v2/extensions/security_test.go | 6 +- .../subnetpools/subnetpools_test.go | 2 +- .../vlantransparent/vlantransparent_test.go | 2 +- .../openstack/networking/v2/networks_test.go | 4 +- .../openstack/networking/v2/ports_test.go | 2 +- .../openstack/networking/v2/subnets_test.go | 2 +- .../objectstorage/v1/versioning_test.go | 8 +-- .../orchestration/v1/stackresources_test.go | 2 +- .../openstack/orchestration/v1/stacks_test.go | 2 +- .../placement/v1/allocationcandidates_test.go | 28 ++++----- .../placement/v1/allocations_test.go | 4 +- .../placement/v1/resourceclasses_test.go | 14 ++--- .../placement/v1/resourceproviders_test.go | 34 +++++------ .../openstack/placement/v1/traits_test.go | 14 ++--- .../v2/sharetransfers_test.go | 4 +- .../v1/conductors/testing/requests_test.go | 4 +- .../v3/volumetypes/testing/requests_test.go | 18 +++--- .../compute/v2/tags/testing/requests_test.go | 4 +- .../clustertemplates/testing/requests_test.go | 2 +- .../v1/nodegroups/testing/requests_test.go | 24 ++++---- .../db/v1/instances/testing/requests_test.go | 2 +- .../v3/users/testing/requests_test.go | 2 +- .../agents/testing/requests_test.go | 10 ++-- .../attributestags/testing/requests_test.go | 4 +- .../extensions/dns/testing/requests_test.go | 4 +- .../external/testing/results_test.go | 4 +- .../fwaas_v2/groups/testing/requests_test.go | 4 +- .../fwaas_v2/rules/testing/requests_test.go | 4 +- .../addressscopes/testing/requests_test.go | 6 +- .../layer3/routers/testing/requests_test.go | 6 +- .../portsbinding/testing/requests_test.go | 4 +- .../portstrustedvif/testing/requests_test.go | 10 ++-- .../qos/policies/testing/requests_test.go | 8 +-- .../subnetpools/testing/requests_test.go | 4 +- .../vlantransparent/testing/requests_test.go | 24 ++++---- .../v2/networks/testing/requests_test.go | 16 +++--- .../v2/ports/testing/requests_test.go | 26 ++++----- .../v2/subnets/testing/requests_test.go | 20 +++---- .../v1/objects/testing/requests_test.go | 12 ++-- .../testing/requests_test.go | 6 +- .../v1/allocations/testing/requests_test.go | 6 +- .../resourceclasses/testing/requests_test.go | 10 ++-- .../testing/requests_test.go | 14 ++--- .../v1/traits/testing/requests_test.go | 10 ++-- .../v2/shares/testing/request_test.go | 2 +- .../v2/sharetypes/testing/requests_test.go | 2 +- testhelper/convenience.go | 57 +++++++++++++++++++ testing/errors_test.go | 8 +-- testing/provider_client_test.go | 6 +- 124 files changed, 424 insertions(+), 367 deletions(-) diff --git a/internal/acceptance/openstack/baremetal/httpbasic/allocations_test.go b/internal/acceptance/openstack/baremetal/httpbasic/allocations_test.go index a34b606c5b..09e2ff12a8 100644 --- a/internal/acceptance/openstack/baremetal/httpbasic/allocations_test.go +++ b/internal/acceptance/openstack/baremetal/httpbasic/allocations_test.go @@ -43,5 +43,5 @@ func TestAllocationsCreateDestroy(t *testing.T) { return false, nil }) th.AssertNoErr(t, err) - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } diff --git a/internal/acceptance/openstack/baremetal/httpbasic/nodes_test.go b/internal/acceptance/openstack/baremetal/httpbasic/nodes_test.go index 9727c6fc2a..af6180d24f 100644 --- a/internal/acceptance/openstack/baremetal/httpbasic/nodes_test.go +++ b/internal/acceptance/openstack/baremetal/httpbasic/nodes_test.go @@ -44,7 +44,7 @@ func TestNodesCreateDestroy(t *testing.T) { }) th.AssertNoErr(t, err) - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestNodesUpdate(t *testing.T) { @@ -68,7 +68,7 @@ func TestNodesUpdate(t *testing.T) { }).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, true, updated.Maintenance) + th.AssertTrue(t, updated.Maintenance) } func TestNodesRAIDConfig(t *testing.T) { diff --git a/internal/acceptance/openstack/baremetal/httpbasic/ports_test.go b/internal/acceptance/openstack/baremetal/httpbasic/ports_test.go index 2c55bd3a08..836b5a98e9 100644 --- a/internal/acceptance/openstack/baremetal/httpbasic/ports_test.go +++ b/internal/acceptance/openstack/baremetal/httpbasic/ports_test.go @@ -47,7 +47,7 @@ func TestPortsCreateDestroy(t *testing.T) { }) th.AssertNoErr(t, err) - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestPortsUpdate(t *testing.T) { diff --git a/internal/acceptance/openstack/baremetal/noauth/allocations_test.go b/internal/acceptance/openstack/baremetal/noauth/allocations_test.go index bdd9902a19..5cc6eff65f 100644 --- a/internal/acceptance/openstack/baremetal/noauth/allocations_test.go +++ b/internal/acceptance/openstack/baremetal/noauth/allocations_test.go @@ -43,5 +43,5 @@ func TestAllocationsCreateDestroy(t *testing.T) { return false, nil }) th.AssertNoErr(t, err) - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } diff --git a/internal/acceptance/openstack/baremetal/noauth/nodes_test.go b/internal/acceptance/openstack/baremetal/noauth/nodes_test.go index 2b04459377..82aca0a967 100644 --- a/internal/acceptance/openstack/baremetal/noauth/nodes_test.go +++ b/internal/acceptance/openstack/baremetal/noauth/nodes_test.go @@ -44,7 +44,7 @@ func TestNodesCreateDestroy(t *testing.T) { }) th.AssertNoErr(t, err) - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestNodesUpdate(t *testing.T) { @@ -68,7 +68,7 @@ func TestNodesUpdate(t *testing.T) { }).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, true, updated.Maintenance) + th.AssertTrue(t, updated.Maintenance) } func TestNodesRAIDConfig(t *testing.T) { diff --git a/internal/acceptance/openstack/baremetal/noauth/ports_test.go b/internal/acceptance/openstack/baremetal/noauth/ports_test.go index a3c419bf30..97fc5c52f8 100644 --- a/internal/acceptance/openstack/baremetal/noauth/ports_test.go +++ b/internal/acceptance/openstack/baremetal/noauth/ports_test.go @@ -47,7 +47,7 @@ func TestPortsCreateDestroy(t *testing.T) { }) th.AssertNoErr(t, err) - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestPortsUpdate(t *testing.T) { diff --git a/internal/acceptance/openstack/baremetal/v1/allocations_test.go b/internal/acceptance/openstack/baremetal/v1/allocations_test.go index 77f408c50a..74405f7384 100644 --- a/internal/acceptance/openstack/baremetal/v1/allocations_test.go +++ b/internal/acceptance/openstack/baremetal/v1/allocations_test.go @@ -41,5 +41,5 @@ func TestAllocationsCreateDestroy(t *testing.T) { return false, nil }) th.AssertNoErr(t, err) - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } diff --git a/internal/acceptance/openstack/baremetal/v1/nodes_test.go b/internal/acceptance/openstack/baremetal/v1/nodes_test.go index d35eff551a..a578c65490 100644 --- a/internal/acceptance/openstack/baremetal/v1/nodes_test.go +++ b/internal/acceptance/openstack/baremetal/v1/nodes_test.go @@ -42,7 +42,7 @@ func TestNodesCreateDestroy(t *testing.T) { return false, nil }) th.AssertNoErr(t, err) - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) th.AssertEquals(t, node.ProvisionState, string(nodes.Enroll)) @@ -110,7 +110,7 @@ func TestNodesUpdate(t *testing.T) { }).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, true, updated.Maintenance) + th.AssertTrue(t, updated.Maintenance) } func TestNodesMaintenance(t *testing.T) { @@ -132,7 +132,7 @@ func TestNodesMaintenance(t *testing.T) { updated, err := nodes.Get(context.TODO(), client, node.UUID).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, true, updated.Maintenance) + th.AssertTrue(t, updated.Maintenance) th.AssertEquals(t, "I'm tired", updated.MaintenanceReason) err = nodes.UnsetMaintenance(context.TODO(), client, node.UUID).ExtractErr() @@ -141,7 +141,7 @@ func TestNodesMaintenance(t *testing.T) { updated, err = nodes.Get(context.TODO(), client, node.UUID).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, false, updated.Maintenance) + th.AssertFalse(t, updated.Maintenance) th.AssertEquals(t, "", updated.MaintenanceReason) } diff --git a/internal/acceptance/openstack/baremetal/v1/ports_test.go b/internal/acceptance/openstack/baremetal/v1/ports_test.go index a28e49dba2..628a75cdae 100644 --- a/internal/acceptance/openstack/baremetal/v1/ports_test.go +++ b/internal/acceptance/openstack/baremetal/v1/ports_test.go @@ -45,7 +45,7 @@ func TestPortsCreateDestroy(t *testing.T) { }) th.AssertNoErr(t, err) - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestPortsUpdate(t *testing.T) { diff --git a/internal/acceptance/openstack/blockstorage/v2/backups_test.go b/internal/acceptance/openstack/blockstorage/v2/backups_test.go index a01edb6612..d406533a2a 100644 --- a/internal/acceptance/openstack/blockstorage/v2/backups_test.go +++ b/internal/acceptance/openstack/blockstorage/v2/backups_test.go @@ -39,7 +39,7 @@ func TestBackupsCRUD(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestBackupsResetStatus(t *testing.T) { diff --git a/internal/acceptance/openstack/blockstorage/v2/snapshots_test.go b/internal/acceptance/openstack/blockstorage/v2/snapshots_test.go index ec74ba0a4e..dd112587f9 100644 --- a/internal/acceptance/openstack/blockstorage/v2/snapshots_test.go +++ b/internal/acceptance/openstack/blockstorage/v2/snapshots_test.go @@ -44,5 +44,5 @@ func TestSnapshots(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } diff --git a/internal/acceptance/openstack/blockstorage/v2/volumes_test.go b/internal/acceptance/openstack/blockstorage/v2/volumes_test.go index 82dcabac28..60a370457f 100644 --- a/internal/acceptance/openstack/blockstorage/v2/volumes_test.go +++ b/internal/acceptance/openstack/blockstorage/v2/volumes_test.go @@ -57,7 +57,7 @@ func TestVolumesCreateDestroy(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestVolumesCreateForceDestroy(t *testing.T) { diff --git a/internal/acceptance/openstack/blockstorage/v2/volumetenants_test.go b/internal/acceptance/openstack/blockstorage/v2/volumetenants_test.go index 45d9babbad..ffb7c24e78 100644 --- a/internal/acceptance/openstack/blockstorage/v2/volumetenants_test.go +++ b/internal/acceptance/openstack/blockstorage/v2/volumetenants_test.go @@ -38,5 +38,5 @@ func TestVolumeTenants(t *testing.T) { err = volumes.ExtractVolumesInto(allPages, &allVolumes) th.AssertNoErr(t, err) - th.AssertEquals(t, true, len(allVolumes) > 0) + th.AssertTrue(t, len(allVolumes) > 0) } diff --git a/internal/acceptance/openstack/blockstorage/v3/backups_test.go b/internal/acceptance/openstack/blockstorage/v3/backups_test.go index eb67418fe3..13f237a327 100644 --- a/internal/acceptance/openstack/blockstorage/v3/backups_test.go +++ b/internal/acceptance/openstack/blockstorage/v3/backups_test.go @@ -37,7 +37,7 @@ func TestBackupsCRUD(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestBackupsResetStatus(t *testing.T) { diff --git a/internal/acceptance/openstack/blockstorage/v3/blockstorage.go b/internal/acceptance/openstack/blockstorage/v3/blockstorage.go index ebb9d59ed1..b3f07747be 100644 --- a/internal/acceptance/openstack/blockstorage/v3/blockstorage.go +++ b/internal/acceptance/openstack/blockstorage/v3/blockstorage.go @@ -168,7 +168,7 @@ func CreateVolumeType(t *testing.T, client *gophercloud.ServiceClient) (*volumet } tools.PrintResource(t, vt) - th.AssertEquals(t, true, vt.IsPublic) + th.AssertTrue(t, vt.IsPublic) th.AssertEquals(t, vt.Name, name) th.AssertEquals(t, vt.Description, description) // TODO: For some reason returned extra_specs are empty even in API reference: https://developer.openstack.org/api-ref/block-storage/v3/?expanded=create-a-volume-type-detail#volume-types-types @@ -201,7 +201,7 @@ func CreateVolumeTypeNoExtraSpecs(t *testing.T, client *gophercloud.ServiceClien } tools.PrintResource(t, vt) - th.AssertEquals(t, true, vt.IsPublic) + th.AssertTrue(t, vt.IsPublic) th.AssertEquals(t, vt.Name, name) th.AssertEquals(t, vt.Description, description) @@ -230,7 +230,7 @@ func CreateVolumeTypeMultiAttach(t *testing.T, client *gophercloud.ServiceClient } tools.PrintResource(t, vt) - th.AssertEquals(t, true, vt.IsPublic) + th.AssertTrue(t, vt.IsPublic) th.AssertEquals(t, vt.Name, name) th.AssertEquals(t, vt.Description, description) th.AssertEquals(t, " True", vt.ExtraSpecs["multiattach"]) @@ -262,7 +262,7 @@ func CreatePrivateVolumeType(t *testing.T, client *gophercloud.ServiceClient) (* } tools.PrintResource(t, vt) - th.AssertEquals(t, false, vt.IsPublic) + th.AssertFalse(t, vt.IsPublic) th.AssertEquals(t, vt.Name, name) th.AssertEquals(t, vt.Description, description) diff --git a/internal/acceptance/openstack/blockstorage/v3/manageablevolumes_test.go b/internal/acceptance/openstack/blockstorage/v3/manageablevolumes_test.go index a555e706cf..cee317df4a 100644 --- a/internal/acceptance/openstack/blockstorage/v3/manageablevolumes_test.go +++ b/internal/acceptance/openstack/blockstorage/v3/manageablevolumes_test.go @@ -53,5 +53,5 @@ func TestManageableVolumes(t *testing.T) { break } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } diff --git a/internal/acceptance/openstack/blockstorage/v3/qos_test.go b/internal/acceptance/openstack/blockstorage/v3/qos_test.go index 686b472f58..2dc5c84d67 100644 --- a/internal/acceptance/openstack/blockstorage/v3/qos_test.go +++ b/internal/acceptance/openstack/blockstorage/v3/qos_test.go @@ -68,7 +68,7 @@ func TestQoS(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) return true, nil }) diff --git a/internal/acceptance/openstack/blockstorage/v3/snapshots_test.go b/internal/acceptance/openstack/blockstorage/v3/snapshots_test.go index 047e72a7ad..f78d76ea83 100644 --- a/internal/acceptance/openstack/blockstorage/v3/snapshots_test.go +++ b/internal/acceptance/openstack/blockstorage/v3/snapshots_test.go @@ -69,7 +69,7 @@ func TestSnapshots(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) return true, nil }) @@ -87,7 +87,7 @@ func TestSnapshots(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) return true, nil }) diff --git a/internal/acceptance/openstack/blockstorage/v3/volumes_test.go b/internal/acceptance/openstack/blockstorage/v3/volumes_test.go index 7ca982f25a..38cd8ef339 100644 --- a/internal/acceptance/openstack/blockstorage/v3/volumes_test.go +++ b/internal/acceptance/openstack/blockstorage/v3/volumes_test.go @@ -60,7 +60,7 @@ func TestVolumes(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) return true, nil }) @@ -98,7 +98,7 @@ func TestVolumesMultiAttach(t *testing.T) { err = volumes.WaitForStatus(ctx, client, vol.ID, "available") th.AssertNoErr(t, err) - th.AssertEquals(t, true, vol.Multiattach) + th.AssertTrue(t, vol.Multiattach) } func TestVolumesCascadeDelete(t *testing.T) { diff --git a/internal/acceptance/openstack/blockstorage/v3/volumetenants_test.go b/internal/acceptance/openstack/blockstorage/v3/volumetenants_test.go index e03be8d3c7..63ba8d7ff1 100644 --- a/internal/acceptance/openstack/blockstorage/v3/volumetenants_test.go +++ b/internal/acceptance/openstack/blockstorage/v3/volumetenants_test.go @@ -36,5 +36,5 @@ func TestVolumeTenants(t *testing.T) { err = volumes.ExtractVolumesInto(allPages, &allVolumes) th.AssertNoErr(t, err) - th.AssertEquals(t, true, len(allVolumes) > 0) + th.AssertTrue(t, len(allVolumes) > 0) } diff --git a/internal/acceptance/openstack/blockstorage/v3/volumetypes_test.go b/internal/acceptance/openstack/blockstorage/v3/volumetypes_test.go index 41ad0091a2..223b7ff4c5 100644 --- a/internal/acceptance/openstack/blockstorage/v3/volumetypes_test.go +++ b/internal/acceptance/openstack/blockstorage/v3/volumetypes_test.go @@ -38,7 +38,7 @@ func TestVolumeTypesCRUD(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) name := vt.Name + "-updated" description := vt.Description + "-updated" diff --git a/internal/acceptance/openstack/compute/v2/attachinterfaces_test.go b/internal/acceptance/openstack/compute/v2/attachinterfaces_test.go index 95ad0ebf2d..d5be1c1b89 100644 --- a/internal/acceptance/openstack/compute/v2/attachinterfaces_test.go +++ b/internal/acceptance/openstack/compute/v2/attachinterfaces_test.go @@ -48,5 +48,5 @@ func TestAttachDetachInterface(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } diff --git a/internal/acceptance/openstack/compute/v2/availabilityzones_test.go b/internal/acceptance/openstack/compute/v2/availabilityzones_test.go index 3b37db49b0..6fda7f0a65 100644 --- a/internal/acceptance/openstack/compute/v2/availabilityzones_test.go +++ b/internal/acceptance/openstack/compute/v2/availabilityzones_test.go @@ -31,7 +31,7 @@ func TestAvailabilityZonesList(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestAvailabilityZonesListDetail(t *testing.T) { @@ -55,5 +55,5 @@ func TestAvailabilityZonesListDetail(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } diff --git a/internal/acceptance/openstack/compute/v2/compute.go b/internal/acceptance/openstack/compute/v2/compute.go index b09b8d7b6e..0d1aca4d7c 100644 --- a/internal/acceptance/openstack/compute/v2/compute.go +++ b/internal/acceptance/openstack/compute/v2/compute.go @@ -173,7 +173,7 @@ func CreateFlavor(t *testing.T, client *gophercloud.ServiceClient) (*flavors.Fla th.AssertEquals(t, 1, flavor.RAM) th.AssertEquals(t, 1, flavor.Disk) th.AssertEquals(t, 1, flavor.VCPUs) - th.AssertEquals(t, true, flavor.IsPublic) + th.AssertTrue(t, flavor.IsPublic) th.AssertEquals(t, flavorDescription, flavor.Description) return flavor, nil @@ -296,7 +296,7 @@ func CreatePrivateFlavor(t *testing.T, client *gophercloud.ServiceClient) (*flav th.AssertEquals(t, 1, flavor.RAM) th.AssertEquals(t, 1, flavor.Disk) th.AssertEquals(t, 1, flavor.VCPUs) - th.AssertEquals(t, false, flavor.IsPublic) + th.AssertFalse(t, flavor.IsPublic) return flavor, nil } diff --git a/internal/acceptance/openstack/compute/v2/diagnostics_test.go b/internal/acceptance/openstack/compute/v2/diagnostics_test.go index e51984bd52..04ba0de043 100644 --- a/internal/acceptance/openstack/compute/v2/diagnostics_test.go +++ b/internal/acceptance/openstack/compute/v2/diagnostics_test.go @@ -28,5 +28,5 @@ func TestDiagnostics(t *testing.T) { tools.PrintResource(t, diag) _, ok := diag["memory"] - th.AssertEquals(t, true, ok) + th.AssertTrue(t, ok) } diff --git a/internal/acceptance/openstack/compute/v2/extension_test.go b/internal/acceptance/openstack/compute/v2/extension_test.go index 8040282289..6db15260dc 100644 --- a/internal/acceptance/openstack/compute/v2/extension_test.go +++ b/internal/acceptance/openstack/compute/v2/extension_test.go @@ -31,7 +31,7 @@ func TestExtensionsList(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestExtensionsGet(t *testing.T) { diff --git a/internal/acceptance/openstack/compute/v2/flavors_test.go b/internal/acceptance/openstack/compute/v2/flavors_test.go index 7a6ca6b2d5..305b07ca47 100644 --- a/internal/acceptance/openstack/compute/v2/flavors_test.go +++ b/internal/acceptance/openstack/compute/v2/flavors_test.go @@ -35,7 +35,7 @@ func TestFlavorsList(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestFlavorsAccessTypeList(t *testing.T) { diff --git a/internal/acceptance/openstack/compute/v2/instance_actions_test.go b/internal/acceptance/openstack/compute/v2/instance_actions_test.go index 01dd9fc72c..9a83a732c0 100644 --- a/internal/acceptance/openstack/compute/v2/instance_actions_test.go +++ b/internal/acceptance/openstack/compute/v2/instance_actions_test.go @@ -39,7 +39,7 @@ func TestInstanceActions(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestInstanceActionsMicroversions(t *testing.T) { @@ -88,7 +88,7 @@ func TestInstanceActionsMicroversions(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) listOpts = instanceactions.ListOpts{ Limit: 1, diff --git a/internal/acceptance/openstack/compute/v2/keypairs_test.go b/internal/acceptance/openstack/compute/v2/keypairs_test.go index 09d28f24f5..6051dff117 100644 --- a/internal/acceptance/openstack/compute/v2/keypairs_test.go +++ b/internal/acceptance/openstack/compute/v2/keypairs_test.go @@ -57,7 +57,7 @@ func TestKeyPairsCreateDelete(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestKeyPairsImportPublicKey(t *testing.T) { @@ -146,7 +146,7 @@ func TestKeyPairsCreateDeleteByID(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) deleteOpts := keypairs.DeleteOpts{ UserID: user.ID, diff --git a/internal/acceptance/openstack/compute/v2/secgroup_test.go b/internal/acceptance/openstack/compute/v2/secgroup_test.go index 0a883d3789..aa312a8239 100644 --- a/internal/acceptance/openstack/compute/v2/secgroup_test.go +++ b/internal/acceptance/openstack/compute/v2/secgroup_test.go @@ -32,7 +32,7 @@ func TestSecGroupsList(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestSecGroupsCRUD(t *testing.T) { @@ -120,7 +120,7 @@ func TestSecGroupsAddGroupToServer(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) t.Logf("Removing group %s from server %s", securityGroup.ID, server.ID) err = secgroups.RemoveServer(context.TODO(), client, server.ID, securityGroup.Name).ExtractErr() @@ -139,5 +139,5 @@ func TestSecGroupsAddGroupToServer(t *testing.T) { } } - th.AssertEquals(t, false, found) + th.AssertFalse(t, found) } diff --git a/internal/acceptance/openstack/compute/v2/servergroup_test.go b/internal/acceptance/openstack/compute/v2/servergroup_test.go index 09d351a7b4..5b27b9e1e9 100644 --- a/internal/acceptance/openstack/compute/v2/servergroup_test.go +++ b/internal/acceptance/openstack/compute/v2/servergroup_test.go @@ -41,7 +41,7 @@ func TestServergroupsCreateDelete(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestServergroupsAffinityPolicy(t *testing.T) { @@ -100,5 +100,5 @@ func TestServergroupsMicroversionCreateDelete(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } diff --git a/internal/acceptance/openstack/compute/v2/servers_test.go b/internal/acceptance/openstack/compute/v2/servers_test.go index cebeb43e5b..7c7c7fb036 100644 --- a/internal/acceptance/openstack/compute/v2/servers_test.go +++ b/internal/acceptance/openstack/compute/v2/servers_test.go @@ -45,7 +45,7 @@ func TestServersCreateDestroy(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) allAddressPages, err := servers.ListAddresses(client, server.ID).AllPages(context.TODO()) th.AssertNoErr(t, err) @@ -97,8 +97,8 @@ func TestServersWithExtensionsCreateDestroy(t *testing.T) { th.AssertEquals(t, servers.RUNNING, int(created.PowerState)) th.AssertEquals(t, "", created.TaskState) th.AssertEquals(t, "active", created.VmState) - th.AssertEquals(t, false, created.LaunchedAt.IsZero()) - th.AssertEquals(t, true, created.TerminatedAt.IsZero()) + th.AssertFalse(t, created.LaunchedAt.IsZero()) + th.AssertTrue(t, created.TerminatedAt.IsZero()) } func TestServersWithoutImageRef(t *testing.T) { @@ -447,7 +447,7 @@ func TestServersActionLock(t *testing.T) { t.Logf("Attempting to delete locked server %s", server.ID) err = servers.Delete(context.TODO(), client, server.ID).ExtractErr() - th.AssertEquals(t, true, err != nil) + th.AssertTrue(t, err != nil) t.Logf("Attempting to unlock server %s", server.ID) err = servers.Unlock(context.TODO(), client, server.ID).ExtractErr() @@ -513,7 +513,7 @@ func TestServersTags(t *testing.T) { // Check single tag. exists, err := tags.Check(context.TODO(), client, server.ID, "tag2").Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, true, exists) + th.AssertTrue(t, exists) // Add new tag. newTags, err := tags.ReplaceAll(context.TODO(), client, server.ID, tags.ReplaceAllOpts{Tags: []string{"tag3", "tag4"}}).Extract() @@ -536,7 +536,7 @@ func TestServersTags(t *testing.T) { // Check that tag doesn't exist anymore. exists, err = tags.Check(context.TODO(), client, server.ID, "tag4").Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, false, exists) + th.AssertFalse(t, exists) // Remove all tags. err = tags.DeleteAll(context.TODO(), client, server.ID).ExtractErr() @@ -565,13 +565,13 @@ func TestServersWithExtendedAttributesCreateDestroy(t *testing.T) { t.Logf("Server With Extended Attributes: %#v", created) - th.AssertEquals(t, true, *created.ReservationID != "") + th.AssertTrue(t, *created.ReservationID != "") th.AssertEquals(t, 0, *created.LaunchIndex) - th.AssertEquals(t, true, *created.RAMDiskID == "") - th.AssertEquals(t, true, *created.KernelID == "") - th.AssertEquals(t, true, *created.Hostname != "") - th.AssertEquals(t, true, *created.RootDeviceName != "") - th.AssertEquals(t, true, created.Userdata == nil) + th.AssertTrue(t, *created.RAMDiskID == "") + th.AssertTrue(t, *created.KernelID == "") + th.AssertTrue(t, *created.Hostname != "") + th.AssertTrue(t, *created.RootDeviceName != "") + th.AssertTrue(t, created.Userdata == nil) } func TestServerNoNetworkCreateDestroy(t *testing.T) { @@ -604,7 +604,7 @@ func TestServerNoNetworkCreateDestroy(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) allAddressPages, err := servers.ListAddresses(client, server.ID).AllPages(context.TODO()) th.AssertNoErr(t, err) diff --git a/internal/acceptance/openstack/compute/v2/services_test.go b/internal/acceptance/openstack/compute/v2/services_test.go index 7b8d8725b5..80f60de47b 100644 --- a/internal/acceptance/openstack/compute/v2/services_test.go +++ b/internal/acceptance/openstack/compute/v2/services_test.go @@ -33,7 +33,7 @@ func TestServicesList(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestServicesListWithOpts(t *testing.T) { @@ -62,5 +62,5 @@ func TestServicesListWithOpts(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } diff --git a/internal/acceptance/openstack/containerinfra/v1/clusters_test.go b/internal/acceptance/openstack/containerinfra/v1/clusters_test.go index a6ffbe5e42..c1ff6ef771 100644 --- a/internal/acceptance/openstack/containerinfra/v1/clusters_test.go +++ b/internal/acceptance/openstack/containerinfra/v1/clusters_test.go @@ -39,7 +39,7 @@ func TestClustersCRUD(t *testing.T) { found = true } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) updateOpts := []clusters.UpdateOptsBuilder{ clusters.UpdateOpts{ Op: clusters.ReplaceOp, @@ -63,7 +63,7 @@ func TestClustersCRUD(t *testing.T) { newCluster, err := clusters.Get(context.TODO(), client, clusterID).Extract() th.AssertNoErr(t, err) th.AssertEquals(t, newCluster.UUID, clusterID) - th.AssertEquals(t, false, newCluster.MasterLBEnabled) + th.AssertFalse(t, newCluster.MasterLBEnabled) allPagesDetail, err := clusters.ListDetail(client, nil).AllPages(context.TODO()) th.AssertNoErr(t, err) @@ -77,7 +77,7 @@ func TestClustersCRUD(t *testing.T) { foundDetail = true } } - th.AssertEquals(t, true, foundDetail) + th.AssertTrue(t, foundDetail) tools.PrintResource(t, newCluster) } diff --git a/internal/acceptance/openstack/containerinfra/v1/clustertemplates_test.go b/internal/acceptance/openstack/containerinfra/v1/clustertemplates_test.go index 91bc67bd8f..1e42c3fcf4 100644 --- a/internal/acceptance/openstack/containerinfra/v1/clustertemplates_test.go +++ b/internal/acceptance/openstack/containerinfra/v1/clustertemplates_test.go @@ -36,7 +36,7 @@ func TestClusterTemplatesCRUD(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) template, err := clustertemplates.Get(context.TODO(), client, clusterTemplate.UUID).Extract() th.AssertNoErr(t, err) @@ -63,8 +63,8 @@ func TestClusterTemplatesCRUD(t *testing.T) { updateClusterTemplate, err := clustertemplates.Update(context.TODO(), client, clusterTemplate.UUID, updateOpts).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, false, updateClusterTemplate.MasterLBEnabled) - th.AssertEquals(t, false, updateClusterTemplate.RegistryEnabled) + th.AssertFalse(t, updateClusterTemplate.MasterLBEnabled) + th.AssertFalse(t, updateClusterTemplate.RegistryEnabled) th.AssertEquals(t, "test", updateClusterTemplate.Labels["test"]) tools.PrintResource(t, updateClusterTemplate) diff --git a/internal/acceptance/openstack/containerinfra/v1/containerinfra.go b/internal/acceptance/openstack/containerinfra/v1/containerinfra.go index 24f8c1959b..978787ef5e 100644 --- a/internal/acceptance/openstack/containerinfra/v1/containerinfra.go +++ b/internal/acceptance/openstack/containerinfra/v1/containerinfra.go @@ -58,7 +58,7 @@ func CreateClusterTemplateCOE(t *testing.T, client *gophercloud.ServiceClient, c } requestID := res.Header.Get("X-OpenStack-Request-Id") - th.AssertEquals(t, true, requestID != "") + th.AssertTrue(t, requestID != "") t.Logf("Cluster Template %s request ID: %s", name, requestID) @@ -235,7 +235,7 @@ func CreateQuota(t *testing.T, client *gophercloud.ServiceClient) (*quotas.Quota } requestID := res.Header.Get("X-OpenStack-Request-Id") - th.AssertEquals(t, true, requestID != "") + th.AssertTrue(t, requestID != "") t.Logf("Quota %s request ID: %s", name, requestID) diff --git a/internal/acceptance/openstack/containerinfra/v1/nodegroups_test.go b/internal/acceptance/openstack/containerinfra/v1/nodegroups_test.go index d6493fa338..0cc10e6dcc 100644 --- a/internal/acceptance/openstack/containerinfra/v1/nodegroups_test.go +++ b/internal/acceptance/openstack/containerinfra/v1/nodegroups_test.go @@ -137,7 +137,7 @@ func testNodeGroupUpdate(t *testing.T, client *gophercloud.ServiceClient, cluste } ng, err = nodegroups.Update(context.TODO(), client, clusterID, nodeGroupID, updateOpts).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, false, ng.MaxNodeCount == nil) + th.AssertFalse(t, ng.MaxNodeCount == nil) th.AssertEquals(t, 5, *ng.MaxNodeCount) updateOpts = []nodegroups.UpdateOptsBuilder{ @@ -154,7 +154,7 @@ func testNodeGroupUpdate(t *testing.T, client *gophercloud.ServiceClient, cluste } ng, err = nodegroups.Update(context.TODO(), client, clusterID, nodeGroupID, updateOpts).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, false, ng.MaxNodeCount == nil) + th.AssertFalse(t, ng.MaxNodeCount == nil) th.AssertEquals(t, 1, ng.MinNodeCount) th.AssertEquals(t, 3, *ng.MaxNodeCount) } diff --git a/internal/acceptance/openstack/dns/v2/recordsets_test.go b/internal/acceptance/openstack/dns/v2/recordsets_test.go index fcdb23210b..20d4408979 100644 --- a/internal/acceptance/openstack/dns/v2/recordsets_test.go +++ b/internal/acceptance/openstack/dns/v2/recordsets_test.go @@ -36,7 +36,7 @@ func TestRecordSetsListByZone(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) listOpts := recordsets.ListOpts{ Limit: 1, @@ -79,7 +79,7 @@ func TestRecordSetsListAll(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) listOpts := recordsets.ListOpts{ Limit: 1, diff --git a/internal/acceptance/openstack/dns/v2/transfers_test.go b/internal/acceptance/openstack/dns/v2/transfers_test.go index 87c78f773e..f171ddf77e 100644 --- a/internal/acceptance/openstack/dns/v2/transfers_test.go +++ b/internal/acceptance/openstack/dns/v2/transfers_test.go @@ -41,7 +41,7 @@ func TestTransferRequestCRUD(t *testing.T) { foundRequest = true } } - th.AssertEquals(t, true, foundRequest) + th.AssertTrue(t, foundRequest) description := "new description" updateOpts := transferRequests.UpdateOpts{ @@ -93,5 +93,5 @@ func TestTransferRequestAccept(t *testing.T) { foundAccept = true } } - th.AssertEquals(t, true, foundAccept) + th.AssertTrue(t, foundAccept) } diff --git a/internal/acceptance/openstack/dns/v2/tsigkeys_test.go b/internal/acceptance/openstack/dns/v2/tsigkeys_test.go index 33d695d487..118781c7a7 100644 --- a/internal/acceptance/openstack/dns/v2/tsigkeys_test.go +++ b/internal/acceptance/openstack/dns/v2/tsigkeys_test.go @@ -39,7 +39,7 @@ func TestTSIGKeysCRUD(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) updateOpts := tsigkeys.UpdateOpts{ Name: tsigkey.Name + "-updated", diff --git a/internal/acceptance/openstack/dns/v2/zones_test.go b/internal/acceptance/openstack/dns/v2/zones_test.go index 9becb6b024..fd26249448 100644 --- a/internal/acceptance/openstack/dns/v2/zones_test.go +++ b/internal/acceptance/openstack/dns/v2/zones_test.go @@ -37,7 +37,7 @@ func TestZonesCRUD(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) description := "" updateOpts := zones.UpdateOpts{ diff --git a/internal/acceptance/openstack/identity/v2/extension_test.go b/internal/acceptance/openstack/identity/v2/extension_test.go index e3ce3e8e58..264cdc008e 100644 --- a/internal/acceptance/openstack/identity/v2/extension_test.go +++ b/internal/acceptance/openstack/identity/v2/extension_test.go @@ -33,7 +33,7 @@ func TestExtensionsList(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestExtensionsGet(t *testing.T) { diff --git a/internal/acceptance/openstack/identity/v2/role_test.go b/internal/acceptance/openstack/identity/v2/role_test.go index 19e4478960..45eb067b95 100644 --- a/internal/acceptance/openstack/identity/v2/role_test.go +++ b/internal/acceptance/openstack/identity/v2/role_test.go @@ -49,7 +49,7 @@ func TestRolesAddToUser(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestRolesList(t *testing.T) { @@ -73,5 +73,5 @@ func TestRolesList(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } diff --git a/internal/acceptance/openstack/identity/v2/tenant_test.go b/internal/acceptance/openstack/identity/v2/tenant_test.go index b5d10eadee..116983c94c 100644 --- a/internal/acceptance/openstack/identity/v2/tenant_test.go +++ b/internal/acceptance/openstack/identity/v2/tenant_test.go @@ -34,7 +34,7 @@ func TestTenantsList(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestTenantsCRUD(t *testing.T) { diff --git a/internal/acceptance/openstack/identity/v2/user_test.go b/internal/acceptance/openstack/identity/v2/user_test.go index 466d053e90..09f776a94c 100644 --- a/internal/acceptance/openstack/identity/v2/user_test.go +++ b/internal/acceptance/openstack/identity/v2/user_test.go @@ -34,7 +34,7 @@ func TestUsersList(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestUsersCreateUpdateDelete(t *testing.T) { diff --git a/internal/acceptance/openstack/identity/v3/applicationcredentials_test.go b/internal/acceptance/openstack/identity/v3/applicationcredentials_test.go index a502c96a44..8580310c40 100644 --- a/internal/acceptance/openstack/identity/v3/applicationcredentials_test.go +++ b/internal/acceptance/openstack/identity/v3/applicationcredentials_test.go @@ -97,7 +97,7 @@ func TestApplicationCredentialsCRD(t *testing.T) { th.AssertEquals(t, applicationCredential.ExpiresAt, expiresAt) th.AssertEquals(t, applicationCredential.Name, createOpts.Name) th.AssertEquals(t, applicationCredential.Description, createOpts.Description) - th.AssertEquals(t, false, applicationCredential.Unrestricted) + th.AssertFalse(t, applicationCredential.Unrestricted) th.AssertEquals(t, applicationCredential.ProjectID, project.ID) checkACroles := rolesToMap(applicationCredential.Roles) @@ -124,7 +124,7 @@ func TestApplicationCredentialsCRD(t *testing.T) { th.AssertEquals(t, getApplicationCredential.ExpiresAt, expiresAt) th.AssertEquals(t, getApplicationCredential.Name, createOpts.Name) th.AssertEquals(t, getApplicationCredential.Description, createOpts.Description) - th.AssertEquals(t, false, getApplicationCredential.Unrestricted) + th.AssertFalse(t, getApplicationCredential.Unrestricted) th.AssertEquals(t, getApplicationCredential.ProjectID, project.ID) checkACroles = rolesToMap(getApplicationCredential.Roles) @@ -156,7 +156,7 @@ func TestApplicationCredentialsCRD(t *testing.T) { th.AssertEquals(t, newApplicationCredential.Name, createOpts.Name) th.AssertEquals(t, newApplicationCredential.Description, createOpts.Description) th.AssertEquals(t, newApplicationCredential.Secret, createOpts.Secret) - th.AssertEquals(t, true, newApplicationCredential.Unrestricted) + th.AssertTrue(t, newApplicationCredential.Unrestricted) th.AssertEquals(t, time.Time{}, newApplicationCredential.ExpiresAt) th.AssertEquals(t, newApplicationCredential.ProjectID, project.ID) @@ -235,7 +235,7 @@ func TestApplicationCredentialsAccessRules(t *testing.T) { th.AssertEquals(t, applicationCredential.ExpiresAt, expiresAt) th.AssertEquals(t, applicationCredential.Name, createOpts.Name) th.AssertEquals(t, applicationCredential.Description, createOpts.Description) - th.AssertEquals(t, false, applicationCredential.Unrestricted) + th.AssertFalse(t, applicationCredential.Unrestricted) for i, rule := range applicationCredential.AccessRules { th.AssertEquals(t, rule.Path, apAccessRules[i].Path) @@ -255,7 +255,7 @@ func TestApplicationCredentialsAccessRules(t *testing.T) { th.AssertEquals(t, getApplicationCredential.ExpiresAt, expiresAt) th.AssertEquals(t, getApplicationCredential.Name, createOpts.Name) th.AssertEquals(t, getApplicationCredential.Description, createOpts.Description) - th.AssertEquals(t, false, getApplicationCredential.Unrestricted) + th.AssertFalse(t, getApplicationCredential.Unrestricted) for i, rule := range applicationCredential.AccessRules { th.AssertEquals(t, rule.Path, apAccessRules[i].Path) diff --git a/internal/acceptance/openstack/identity/v3/domains_test.go b/internal/acceptance/openstack/identity/v3/domains_test.go index 6d32615bfd..48d32b6e18 100644 --- a/internal/acceptance/openstack/identity/v3/domains_test.go +++ b/internal/acceptance/openstack/identity/v3/domains_test.go @@ -55,7 +55,7 @@ func TestDomainsList(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestDomainsGet(t *testing.T) { diff --git a/internal/acceptance/openstack/identity/v3/endpoint_test.go b/internal/acceptance/openstack/identity/v3/endpoint_test.go index 01f4ff171b..26e86c5352 100644 --- a/internal/acceptance/openstack/identity/v3/endpoint_test.go +++ b/internal/acceptance/openstack/identity/v3/endpoint_test.go @@ -36,7 +36,7 @@ func TestEndpointsList(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestEndpointsGet(t *testing.T) { diff --git a/internal/acceptance/openstack/identity/v3/federation_test.go b/internal/acceptance/openstack/identity/v3/federation_test.go index 35986dc15c..3b92073668 100644 --- a/internal/acceptance/openstack/identity/v3/federation_test.go +++ b/internal/acceptance/openstack/identity/v3/federation_test.go @@ -118,5 +118,5 @@ func TestMappingsCRUD(t *testing.T) { th.AssertNoErr(t, err) resp := federation.GetMapping(context.TODO(), client, mappingName) - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(resp.Err, http.StatusNotFound)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(resp.Err, http.StatusNotFound)) } diff --git a/internal/acceptance/openstack/identity/v3/groups_test.go b/internal/acceptance/openstack/identity/v3/groups_test.go index bc353d5ca5..c482ae4fdb 100644 --- a/internal/acceptance/openstack/identity/v3/groups_test.go +++ b/internal/acceptance/openstack/identity/v3/groups_test.go @@ -83,7 +83,7 @@ func TestGroupCRUD(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) listOpts.Filters = map[string]string{ "name__contains": "TEST", @@ -105,7 +105,7 @@ func TestGroupCRUD(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) listOpts.Filters = map[string]string{ "name__contains": "foo", @@ -127,7 +127,7 @@ func TestGroupCRUD(t *testing.T) { } } - th.AssertEquals(t, false, found) + th.AssertFalse(t, found) // Get the recently created group by ID p, err := groups.Get(context.TODO(), client, group.ID).Extract() diff --git a/internal/acceptance/openstack/identity/v3/oauth1_test.go b/internal/acceptance/openstack/identity/v3/oauth1_test.go index 88307f4a77..782510fc18 100644 --- a/internal/acceptance/openstack/identity/v3/oauth1_test.go +++ b/internal/acceptance/openstack/identity/v3/oauth1_test.go @@ -179,7 +179,7 @@ func oauth1MethodTest(t *testing.T, client *gophercloud.ServiceClient, consumer found = true } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } // Get access token role @@ -193,7 +193,7 @@ func oauth1MethodTest(t *testing.T, client *gophercloud.ServiceClient, consumer found = true } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) // Test auth using OAuth1 newClient, err := clients.NewIdentityV3UnauthenticatedClient() diff --git a/internal/acceptance/openstack/identity/v3/policies_test.go b/internal/acceptance/openstack/identity/v3/policies_test.go index 0b23bdd9f5..91d65db976 100644 --- a/internal/acceptance/openstack/identity/v3/policies_test.go +++ b/internal/acceptance/openstack/identity/v3/policies_test.go @@ -71,7 +71,7 @@ func TestPoliciesCRUD(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) listOpts.Filters = map[string]string{ "type__contains": "json", @@ -93,7 +93,7 @@ func TestPoliciesCRUD(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) listOpts.Filters = map[string]string{ "type__contains": "foobar", @@ -115,7 +115,7 @@ func TestPoliciesCRUD(t *testing.T) { } } - th.AssertEquals(t, false, found) + th.AssertFalse(t, found) gotPolicy, err := policies.Get(context.TODO(), client, policy.ID).Extract() th.AssertNoErr(t, err) diff --git a/internal/acceptance/openstack/identity/v3/projects_test.go b/internal/acceptance/openstack/identity/v3/projects_test.go index 82d83bda16..2ce5cded9a 100644 --- a/internal/acceptance/openstack/identity/v3/projects_test.go +++ b/internal/acceptance/openstack/identity/v3/projects_test.go @@ -55,7 +55,7 @@ func TestProjectsList(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) listOpts.Filters = map[string]string{ "name__contains": "dmi", @@ -76,7 +76,7 @@ func TestProjectsList(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) listOpts.Filters = map[string]string{ "name__contains": "foo", @@ -97,7 +97,7 @@ func TestProjectsList(t *testing.T) { } } - th.AssertEquals(t, false, found) + th.AssertFalse(t, found) } func TestProjectsGet(t *testing.T) { @@ -247,7 +247,7 @@ func TestProjectsTags(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) // Search using all tags, including a not existing one listOpts = projects.ListOpts{ @@ -282,7 +282,7 @@ func TestProjectsTags(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) // Search not matching any single tag listOpts = projects.ListOpts{ @@ -304,7 +304,7 @@ func TestProjectsTags(t *testing.T) { } } - th.AssertEquals(t, false, found) + th.AssertFalse(t, found) // Search matching not all tags listOpts = projects.ListOpts{ @@ -326,7 +326,7 @@ func TestProjectsTags(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) // Update the tags updateOpts := projects.UpdateOpts{ diff --git a/internal/acceptance/openstack/identity/v3/roles_test.go b/internal/acceptance/openstack/identity/v3/roles_test.go index 499888a7e7..f754232285 100644 --- a/internal/acceptance/openstack/identity/v3/roles_test.go +++ b/internal/acceptance/openstack/identity/v3/roles_test.go @@ -96,7 +96,7 @@ func TestRolesCRUD(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) description := "updated role test" updateOpts := roles.UpdateOpts{ Description: &description, @@ -158,7 +158,7 @@ func TestRolesFilterList(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) listOpts.Filters = map[string]string{ "name__contains": "reader", @@ -180,7 +180,7 @@ func TestRolesFilterList(t *testing.T) { } } - th.AssertEquals(t, false, found) + th.AssertFalse(t, found) } func TestRoleListAssignmentIncludeNamesAndSubtree(t *testing.T) { @@ -248,7 +248,7 @@ func TestRoleListAssignmentIncludeNamesAndSubtree(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestRoleListAssignmentForUserOnProject(t *testing.T) { @@ -310,7 +310,7 @@ func TestRoleListAssignmentForUserOnProject(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestRoleListAssignmentForUserOnDomain(t *testing.T) { @@ -375,7 +375,7 @@ func TestRoleListAssignmentForUserOnDomain(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestRoleListAssignmentForGroupOnProject(t *testing.T) { @@ -440,7 +440,7 @@ func TestRoleListAssignmentForGroupOnProject(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestRoleListAssignmentForGroupOnDomain(t *testing.T) { @@ -508,7 +508,7 @@ func TestRoleListAssignmentForGroupOnDomain(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestRolesAssignToUserOnProject(t *testing.T) { @@ -578,7 +578,7 @@ func TestRolesAssignToUserOnProject(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestRolesAssignToUserOnDomain(t *testing.T) { @@ -651,7 +651,7 @@ func TestRolesAssignToUserOnDomain(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestRolesAssignToGroupOnDomain(t *testing.T) { @@ -727,7 +727,7 @@ func TestRolesAssignToGroupOnDomain(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestRolesAssignToGroupOnProject(t *testing.T) { @@ -800,7 +800,7 @@ func TestRolesAssignToGroupOnProject(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestCRUDRoleInferenceRule(t *testing.T) { diff --git a/internal/acceptance/openstack/identity/v3/service_test.go b/internal/acceptance/openstack/identity/v3/service_test.go index a850952a71..7878c83207 100644 --- a/internal/acceptance/openstack/identity/v3/service_test.go +++ b/internal/acceptance/openstack/identity/v3/service_test.go @@ -37,7 +37,7 @@ func TestServicesList(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestServicesCRUD(t *testing.T) { diff --git a/internal/acceptance/openstack/identity/v3/trusts_test.go b/internal/acceptance/openstack/identity/v3/trusts_test.go index db20d24883..1f3145accb 100644 --- a/internal/acceptance/openstack/identity/v3/trusts_test.go +++ b/internal/acceptance/openstack/identity/v3/trusts_test.go @@ -112,7 +112,7 @@ func TestTrustCRUD(t *testing.T) { p, err := trusts.Get(context.TODO(), client, trust.ID).Extract() th.AssertNoErr(t, err) th.AssertEquals(t, p.ExpiresAt, expiresAt) - th.AssertEquals(t, true, p.DeletedAt.IsZero()) + th.AssertTrue(t, p.DeletedAt.IsZero()) tools.PrintResource(t, p) diff --git a/internal/acceptance/openstack/identity/v3/users_test.go b/internal/acceptance/openstack/identity/v3/users_test.go index a1b310a6a2..1aac48fdc8 100644 --- a/internal/acceptance/openstack/identity/v3/users_test.go +++ b/internal/acceptance/openstack/identity/v3/users_test.go @@ -41,7 +41,7 @@ func TestUsersList(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) listOpts.Filters = map[string]string{ "name__contains": "dmi", @@ -63,7 +63,7 @@ func TestUsersList(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) listOpts.Filters = map[string]string{ "name__contains": "foo", @@ -85,7 +85,7 @@ func TestUsersList(t *testing.T) { } } - th.AssertEquals(t, false, found) + th.AssertFalse(t, found) } func TestUsersGet(t *testing.T) { @@ -251,7 +251,7 @@ func TestUsersGroups(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) found = false allUserPages, err := users.ListInGroup(client, group.ID, nil).AllPages(context.TODO()) @@ -269,7 +269,7 @@ func TestUsersGroups(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) ok, err := users.IsMemberOfGroup(context.TODO(), client, group.ID, user.ID).Extract() if err != nil { @@ -298,7 +298,7 @@ func TestUsersGroups(t *testing.T) { } } - th.AssertEquals(t, false, found) + th.AssertFalse(t, found) found = false allUserPages, err = users.ListInGroup(client, group.ID, nil).AllPages(context.TODO()) @@ -316,7 +316,7 @@ func TestUsersGroups(t *testing.T) { } } - th.AssertEquals(t, false, found) + th.AssertFalse(t, found) } diff --git a/internal/acceptance/openstack/image/v2/images_test.go b/internal/acceptance/openstack/image/v2/images_test.go index 0b560c1ee8..e8bb2ea1d2 100644 --- a/internal/acceptance/openstack/image/v2/images_test.go +++ b/internal/acceptance/openstack/image/v2/images_test.go @@ -66,7 +66,7 @@ func TestImagesListAllPages(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestImagesListByDate(t *testing.T) { @@ -175,7 +175,7 @@ func TestImagesUpdate(t *testing.T) { tools.PrintResource(t, newImage.Properties) th.AssertEquals(t, newImage.Name, image.Name+"foo") - th.AssertEquals(t, true, newImage.Protected) + th.AssertTrue(t, newImage.Protected) sort.Strings(newTags) sort.Strings(newImage.Tags) diff --git a/internal/acceptance/openstack/keymanager/v1/acls_test.go b/internal/acceptance/openstack/keymanager/v1/acls_test.go index 2045c51e49..5e5b620022 100644 --- a/internal/acceptance/openstack/keymanager/v1/acls_test.go +++ b/internal/acceptance/openstack/keymanager/v1/acls_test.go @@ -50,7 +50,7 @@ func TestACLCRUD(t *testing.T) { tools.PrintResource(t, acl) tools.PrintResource(t, (*acl)["read"].Created) th.AssertEquals(t, 1, len((*acl)["read"].Users)) - th.AssertEquals(t, false, (*acl)["read"].ProjectAccess) + th.AssertFalse(t, (*acl)["read"].ProjectAccess) newUsers := []string{} updateOpts := acls.SetOpts{ @@ -69,7 +69,7 @@ func TestACLCRUD(t *testing.T) { tools.PrintResource(t, acl) tools.PrintResource(t, (*acl)["read"].Created) th.AssertEquals(t, 0, len((*acl)["read"].Users)) - th.AssertEquals(t, false, (*acl)["read"].ProjectAccess) + th.AssertFalse(t, (*acl)["read"].ProjectAccess) container, err := CreateGenericContainer(t, client, secret) th.AssertNoErr(t, err) @@ -93,7 +93,7 @@ func TestACLCRUD(t *testing.T) { tools.PrintResource(t, acl) tools.PrintResource(t, (*acl)["read"].Created) th.AssertEquals(t, 1, len((*acl)["read"].Users)) - th.AssertEquals(t, false, (*acl)["read"].ProjectAccess) + th.AssertFalse(t, (*acl)["read"].ProjectAccess) aclRef, err = acls.UpdateContainerACL(context.TODO(), client, containerID, updateOpts).Extract() th.AssertNoErr(t, err) @@ -104,5 +104,5 @@ func TestACLCRUD(t *testing.T) { tools.PrintResource(t, acl) tools.PrintResource(t, (*acl)["read"].Created) th.AssertEquals(t, 0, len((*acl)["read"].Users)) - th.AssertEquals(t, false, (*acl)["read"].ProjectAccess) + th.AssertFalse(t, (*acl)["read"].ProjectAccess) } diff --git a/internal/acceptance/openstack/keymanager/v1/containers_test.go b/internal/acceptance/openstack/keymanager/v1/containers_test.go index d16e385d9e..0e56b0971d 100644 --- a/internal/acceptance/openstack/keymanager/v1/containers_test.go +++ b/internal/acceptance/openstack/keymanager/v1/containers_test.go @@ -53,7 +53,7 @@ func TestGenericContainersCRUD(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestCertificateContainer(t *testing.T) { @@ -197,5 +197,5 @@ func TestContainerConsumersCRUD(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } diff --git a/internal/acceptance/openstack/keymanager/v1/orders_test.go b/internal/acceptance/openstack/keymanager/v1/orders_test.go index 75b098c3fe..496f2871a0 100644 --- a/internal/acceptance/openstack/keymanager/v1/orders_test.go +++ b/internal/acceptance/openstack/keymanager/v1/orders_test.go @@ -49,7 +49,7 @@ func TestOrdersCRUD(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestOrdersAsymmetric(t *testing.T) { diff --git a/internal/acceptance/openstack/keymanager/v1/secrets_test.go b/internal/acceptance/openstack/keymanager/v1/secrets_test.go index ec81b3e433..33fed359ba 100644 --- a/internal/acceptance/openstack/keymanager/v1/secrets_test.go +++ b/internal/acceptance/openstack/keymanager/v1/secrets_test.go @@ -52,7 +52,7 @@ func TestSecretsCRUD(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestSecretsDelayedPayload(t *testing.T) { diff --git a/internal/acceptance/openstack/loadbalancer/v2/loadbalancer.go b/internal/acceptance/openstack/loadbalancer/v2/loadbalancer.go index 0b707dac71..46aa05fcc4 100644 --- a/internal/acceptance/openstack/loadbalancer/v2/loadbalancer.go +++ b/internal/acceptance/openstack/loadbalancer/v2/loadbalancer.go @@ -154,7 +154,7 @@ func CreateLoadBalancer(t *testing.T, client *gophercloud.ServiceClient, subnetI th.AssertEquals(t, lb.Name, lbName) th.AssertEquals(t, lb.Description, lbDescription) th.AssertEquals(t, lb.VipSubnetID, subnetID) - th.AssertEquals(t, true, lb.AdminStateUp) + th.AssertTrue(t, lb.AdminStateUp) if len(tags) > 0 { th.AssertDeepEquals(t, lb.Tags, tags) @@ -252,7 +252,7 @@ func CreateLoadBalancerFullyPopulated(t *testing.T, client *gophercloud.ServiceC th.AssertEquals(t, lb.Name, lbName) th.AssertEquals(t, lb.Description, lbDescription) th.AssertEquals(t, lb.VipSubnetID, subnetID) - th.AssertEquals(t, true, lb.AdminStateUp) + th.AssertTrue(t, lb.AdminStateUp) th.AssertEquals(t, 1, len(lb.Listeners)) th.AssertEquals(t, lb.Listeners[0].Name, listenerName) @@ -749,7 +749,7 @@ func CreateFlavor(t *testing.T, client *gophercloud.ServiceClient, flavorProfile th.AssertEquals(t, flavorName, flavor.Name) th.AssertEquals(t, description, flavor.Description) th.AssertEquals(t, flavorProfile.ID, flavor.FlavorProfileID) - th.AssertEquals(t, false, flavor.Enabled) + th.AssertFalse(t, flavor.Enabled) return flavor, nil } diff --git a/internal/acceptance/openstack/networking/v2/extensions/attributestags_test.go b/internal/acceptance/openstack/networking/v2/extensions/attributestags_test.go index c691a575f3..6111fb2dc6 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/attributestags_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/attributestags_test.go @@ -65,10 +65,10 @@ func TestTags(t *testing.T) { // Confirm tags exist/don't exist exists, err := attributestags.Confirm(context.TODO(), client, "networks", network.ID, "d").Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, true, exists) + th.AssertTrue(t, exists) noexists, err := attributestags.Confirm(context.TODO(), client, "networks", network.ID, "a").Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, false, noexists) + th.AssertFalse(t, noexists) // Delete all tags err = attributestags.DeleteAll(context.TODO(), client, "networks", network.ID).ExtractErr() diff --git a/internal/acceptance/openstack/networking/v2/extensions/bgpvpns/bgpvpns_test.go b/internal/acceptance/openstack/networking/v2/extensions/bgpvpns/bgpvpns_test.go index 3c915901e8..6880121e29 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/bgpvpns/bgpvpns_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/bgpvpns/bgpvpns_test.go @@ -168,7 +168,7 @@ func TestBGPVPNRouterAssociationCRUD(t *testing.T) { assocUpdate, err := bgpvpns.UpdateRouterAssociation(context.TODO(), client, bgpVpnCreated.ID, assoc.ID, assocUpdOpts).Extract() th.AssertNoErr(t, err) th.AssertEquals(t, routerCreated.ID, assocUpdate.RouterID) - th.AssertEquals(t, false, assocUpdate.AdvertiseExtraRoutes) + th.AssertFalse(t, assocUpdate.AdvertiseExtraRoutes) // List all Router Associations allPages, err := bgpvpns.ListRouterAssociations(client, bgpVpnCreated.ID, bgpvpns.ListRouterAssociationsOpts{}).AllPages(context.TODO()) @@ -241,7 +241,7 @@ func TestBGPVPNPortAssociationCRUD(t *testing.T) { assocUpdate, err := bgpvpns.UpdatePortAssociation(context.TODO(), client, bgpVpnCreated.ID, assoc.ID, assocUpdOpts).Extract() th.AssertNoErr(t, err) th.AssertEquals(t, port.ID, assocUpdate.PortID) - th.AssertEquals(t, false, assocUpdate.AdvertiseFixedIPs) + th.AssertFalse(t, assocUpdate.AdvertiseFixedIPs) // List all Port Associations allPages, err := bgpvpns.ListPortAssociations(client, bgpVpnCreated.ID, bgpvpns.ListPortAssociationsOpts{}).AllPages(context.TODO()) diff --git a/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/groups_test.go b/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/groups_test.go index 3b8b4b5913..cadde9cc91 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/groups_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/groups_test.go @@ -102,5 +102,5 @@ func TestGroupCRUD(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } diff --git a/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/policy_test.go b/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/policy_test.go index 5467db42d0..5cc4862f04 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/policy_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/policy_test.go @@ -83,5 +83,5 @@ func TestPolicyCRUD(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } diff --git a/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/rule_test.go b/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/rule_test.go index 54b18384d4..329d80cf56 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/rule_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/rule_test.go @@ -68,5 +68,5 @@ func TestRuleCRUD(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } diff --git a/internal/acceptance/openstack/networking/v2/extensions/layer3/addressscopes_test.go b/internal/acceptance/openstack/networking/v2/extensions/layer3/addressscopes_test.go index 9daad75037..8e83725f07 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/layer3/addressscopes_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/layer3/addressscopes_test.go @@ -50,5 +50,5 @@ func TestAddressScopesCRUD(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } diff --git a/internal/acceptance/openstack/networking/v2/extensions/layer3/floatingips_test.go b/internal/acceptance/openstack/networking/v2/extensions/layer3/floatingips_test.go index aaecb86999..beebce75f7 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/layer3/floatingips_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/layer3/floatingips_test.go @@ -44,7 +44,7 @@ func TestLayer3FloatingIPsCreateDelete(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestLayer3FloatingIPsExternalCreateDelete(t *testing.T) { diff --git a/internal/acceptance/openstack/networking/v2/extensions/layer3/l3_scheduling_test.go b/internal/acceptance/openstack/networking/v2/extensions/layer3/l3_scheduling_test.go index 3efd72a7c5..cb57ee6b01 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/layer3/l3_scheduling_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/layer3/l3_scheduling_test.go @@ -64,7 +64,7 @@ func TestLayer3RouterScheduling(t *testing.T) { // List routers on hosting agent routersOnHostingAgent, err := agents.ListL3Routers(context.TODO(), client, hostingAgent.ID).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, false, containsRouterFunc(routersOnHostingAgent, router.ID)) + th.AssertFalse(t, containsRouterFunc(routersOnHostingAgent, router.ID)) t.Logf("Router %s is not scheduled on %s", router.ID, hostingAgent.ID) // schedule back @@ -74,6 +74,6 @@ func TestLayer3RouterScheduling(t *testing.T) { // List hosting agent after readding routersOnHostingAgent, err = agents.ListL3Routers(context.TODO(), client, hostingAgent.ID).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, true, containsRouterFunc(routersOnHostingAgent, router.ID)) + th.AssertTrue(t, containsRouterFunc(routersOnHostingAgent, router.ID)) t.Logf("Router %s is scheduled on %s", router.ID, hostingAgent.ID) } diff --git a/internal/acceptance/openstack/networking/v2/extensions/layer3/portforwardings_test.go b/internal/acceptance/openstack/networking/v2/extensions/layer3/portforwardings_test.go index ad99ffff38..29f3ba62d0 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/layer3/portforwardings_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/layer3/portforwardings_test.go @@ -118,7 +118,7 @@ func TestLayer3PortForwardingsCreateDelete(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) found = false for _, pf := range allPFs { @@ -127,6 +127,6 @@ func TestLayer3PortForwardingsCreateDelete(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } diff --git a/internal/acceptance/openstack/networking/v2/extensions/layer3/routers_test.go b/internal/acceptance/openstack/networking/v2/extensions/layer3/routers_test.go index c751abcfb4..639da4c45e 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/layer3/routers_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/layer3/routers_test.go @@ -59,7 +59,7 @@ func TestLayer3RouterCreateDelete(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestLayer3ExternalRouterCreateDelete(t *testing.T) { @@ -212,7 +212,7 @@ func TestLayer3RouterAgents(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestLayer3RouterRevision(t *testing.T) { diff --git a/internal/acceptance/openstack/networking/v2/extensions/qos/policies/policies_test.go b/internal/acceptance/openstack/networking/v2/extensions/qos/policies/policies_test.go index 04b244fd19..c25934ea07 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/qos/policies/policies_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/qos/policies/policies_test.go @@ -58,7 +58,7 @@ func TestPoliciesCRUD(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestPoliciesRevision(t *testing.T) { diff --git a/internal/acceptance/openstack/networking/v2/extensions/qos/rules/rules_test.go b/internal/acceptance/openstack/networking/v2/extensions/qos/rules/rules_test.go index d5b80f78e8..eef5ca5136 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/qos/rules/rules_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/qos/rules/rules_test.go @@ -58,7 +58,7 @@ func TestBandwidthLimitRulesCRUD(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestDSCPMarkingRulesCRUD(t *testing.T) { @@ -104,7 +104,7 @@ func TestDSCPMarkingRulesCRUD(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestMinimumBandwidthRulesCRUD(t *testing.T) { @@ -150,5 +150,5 @@ func TestMinimumBandwidthRulesCRUD(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } diff --git a/internal/acceptance/openstack/networking/v2/extensions/security_test.go b/internal/acceptance/openstack/networking/v2/extensions/security_test.go index 526b2fb2be..30e370c376 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/security_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/security_test.go @@ -22,7 +22,7 @@ func TestSecurityGroupsCreateUpdateDelete(t *testing.T) { group, err := CreateSecurityGroup(t, client) th.AssertNoErr(t, err) defer DeleteSecurityGroup(t, client, group.ID) - th.AssertEquals(t, true, group.Stateful) + th.AssertTrue(t, group.Stateful) rule, err := CreateSecurityGroupRule(t, client, group.ID) th.AssertNoErr(t, err) @@ -50,7 +50,7 @@ func TestSecurityGroupsCreateUpdateDelete(t *testing.T) { tools.PrintResource(t, newGroup) th.AssertEquals(t, newGroup.Name, name) th.AssertEquals(t, newGroup.Description, description) - th.AssertEquals(t, false, newGroup.Stateful) + th.AssertFalse(t, newGroup.Stateful) listOpts := groups.ListOpts{} allPages, err := groups.List(client, listOpts).AllPages(context.TODO()) @@ -66,7 +66,7 @@ func TestSecurityGroupsCreateUpdateDelete(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestSecurityGroupsPort(t *testing.T) { diff --git a/internal/acceptance/openstack/networking/v2/extensions/subnetpools/subnetpools_test.go b/internal/acceptance/openstack/networking/v2/extensions/subnetpools/subnetpools_test.go index 6f148e132f..3070ecd868 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/subnetpools/subnetpools_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/subnetpools/subnetpools_test.go @@ -54,7 +54,7 @@ func TestSubnetPoolsCRUD(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestSubnetPoolsRevision(t *testing.T) { diff --git a/internal/acceptance/openstack/networking/v2/extensions/vlantransparent/vlantransparent_test.go b/internal/acceptance/openstack/networking/v2/extensions/vlantransparent/vlantransparent_test.go index bf4b3d4a0f..29ff0a061b 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/vlantransparent/vlantransparent_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/vlantransparent/vlantransparent_test.go @@ -38,5 +38,5 @@ func TestVLANTransparentCRUD(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } diff --git a/internal/acceptance/openstack/networking/v2/networks_test.go b/internal/acceptance/openstack/networking/v2/networks_test.go index 5ca5019aa2..fe641b3f8b 100644 --- a/internal/acceptance/openstack/networking/v2/networks_test.go +++ b/internal/acceptance/openstack/networking/v2/networks_test.go @@ -51,7 +51,7 @@ func TestNetworksExternalList(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) iFalse := false networkListOpts = networks.ListOpts{ @@ -118,7 +118,7 @@ func TestNetworksCRUD(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestNetworksPortSecurityCRUD(t *testing.T) { diff --git a/internal/acceptance/openstack/networking/v2/ports_test.go b/internal/acceptance/openstack/networking/v2/ports_test.go index e2a385e529..4729862fc0 100644 --- a/internal/acceptance/openstack/networking/v2/ports_test.go +++ b/internal/acceptance/openstack/networking/v2/ports_test.go @@ -74,7 +74,7 @@ func TestPortsCRUD(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) ipAddress := port.FixedIPs[0].IPAddress t.Logf("Port has IP address: %s", ipAddress) diff --git a/internal/acceptance/openstack/networking/v2/subnets_test.go b/internal/acceptance/openstack/networking/v2/subnets_test.go index e5f5cbf6b2..7c84b910a4 100644 --- a/internal/acceptance/openstack/networking/v2/subnets_test.go +++ b/internal/acceptance/openstack/networking/v2/subnets_test.go @@ -62,7 +62,7 @@ func TestSubnetCRUD(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestSubnetsServiceType(t *testing.T) { diff --git a/internal/acceptance/openstack/objectstorage/v1/versioning_test.go b/internal/acceptance/openstack/objectstorage/v1/versioning_test.go index 7d52c8f1cc..884e784357 100644 --- a/internal/acceptance/openstack/objectstorage/v1/versioning_test.go +++ b/internal/acceptance/openstack/objectstorage/v1/versioning_test.go @@ -47,7 +47,7 @@ func TestObjectsVersioning(t *testing.T) { get, err := containers.Get(context.TODO(), client, cName, nil).Extract() th.AssertNoErr(t, err) t.Logf("Get container headers: %+v\n", get) - th.AssertEquals(t, true, get.VersionsEnabled) + th.AssertTrue(t, get.VersionsEnabled) // Create a slice of buffers to hold the test object content. oContents := make([]string, numObjects) @@ -85,7 +85,7 @@ func TestObjectsVersioning(t *testing.T) { get, err := containers.Get(context.TODO(), client, cName, nil).Extract() th.AssertNoErr(t, err) t.Logf("Get container headers: %+v\n", get) - th.AssertEquals(t, false, get.VersionsEnabled) + th.AssertFalse(t, get.VersionsEnabled) // delete all object versions before deleting the container currentVersionIDs := make([]string, numObjects) @@ -154,9 +154,9 @@ func TestObjectsVersioning(t *testing.T) { // ensure proper versioning attributes are set for i, obj := range ois { if i%2 == 0 { - th.AssertEquals(t, true, obj.IsLatest) + th.AssertTrue(t, obj.IsLatest) } else { - th.AssertEquals(t, false, obj.IsLatest) + th.AssertFalse(t, obj.IsLatest) } if obj.VersionID == "" { t.Fatalf("Unexpected empty version_id for the %s object", obj.Name) diff --git a/internal/acceptance/openstack/orchestration/v1/stackresources_test.go b/internal/acceptance/openstack/orchestration/v1/stackresources_test.go index 8e870050e0..71b068f11d 100644 --- a/internal/acceptance/openstack/orchestration/v1/stackresources_test.go +++ b/internal/acceptance/openstack/orchestration/v1/stackresources_test.go @@ -53,5 +53,5 @@ func TestStackResources(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } diff --git a/internal/acceptance/openstack/orchestration/v1/stacks_test.go b/internal/acceptance/openstack/orchestration/v1/stacks_test.go index 2dae18badb..e77a63dfdd 100644 --- a/internal/acceptance/openstack/orchestration/v1/stacks_test.go +++ b/internal/acceptance/openstack/orchestration/v1/stacks_test.go @@ -48,5 +48,5 @@ func TestStacksCRUD(t *testing.T) { } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } diff --git a/internal/acceptance/openstack/placement/v1/allocationcandidates_test.go b/internal/acceptance/openstack/placement/v1/allocationcandidates_test.go index d3b70ca87d..9483ecb73a 100644 --- a/internal/acceptance/openstack/placement/v1/allocationcandidates_test.go +++ b/internal/acceptance/openstack/placement/v1/allocationcandidates_test.go @@ -76,17 +76,17 @@ func TestAllocationCandidatesList(t *testing.T) { result, err := allocationcandidates.ExtractAllocationCandidates(page) th.AssertNoErr(t, err) - th.AssertEquals(t, true, len(result.AllocationRequests) > 0) + th.AssertTrue(t, len(result.AllocationRequests) > 0) // Assert: The provider's summary contains the exact inventory we seeded: // VCPU total=8, reserved=0 → capacity=8, used=0. summary, present := result.ProviderSummaries[rpUUID] - th.AssertEquals(t, true, present) + th.AssertTrue(t, present) vcpuSummary, present := summary.Resources["VCPU"] - th.AssertEquals(t, true, present) + th.AssertTrue(t, present) th.AssertEquals(t, 8, vcpuSummary.Capacity) th.AssertEquals(t, 0, vcpuSummary.Used) - th.AssertEquals(t, true, slices.Contains(*summary.Traits, "COMPUTE_NODE")) + th.AssertTrue(t, slices.Contains(*summary.Traits, "COMPUTE_NODE")) // It is a root provider: root UUID equals its own UUID, parent is absent. th.AssertEquals(t, rpUUID, *summary.RootProviderUUID) th.AssertEquals(t, (*string)(nil), summary.ParentProviderUUID) @@ -126,15 +126,15 @@ func TestAllocationCandidatesListPre129(t *testing.T) { result, err := allocationcandidates.ExtractAllocationCandidates(page) th.AssertNoErr(t, err) - th.AssertEquals(t, true, len(result.AllocationRequests) > 0) + th.AssertTrue(t, len(result.AllocationRequests) > 0) summary, present := result.ProviderSummaries[rpUUID] - th.AssertEquals(t, true, present) + th.AssertTrue(t, present) vcpuSummary, present := summary.Resources["VCPU"] - th.AssertEquals(t, true, present) + th.AssertTrue(t, present) th.AssertEquals(t, 8, vcpuSummary.Capacity) th.AssertEquals(t, 0, vcpuSummary.Used) - th.AssertEquals(t, true, slices.Contains(*summary.Traits, "COMPUTE_NODE")) + th.AssertTrue(t, slices.Contains(*summary.Traits, "COMPUTE_NODE")) // Root/parent UUIDs are absent below 1.29. th.AssertEquals(t, (*string)(nil), summary.RootProviderUUID) th.AssertEquals(t, (*string)(nil), summary.ParentProviderUUID) @@ -164,8 +164,8 @@ func TestAllocationCandidatesList110(t *testing.T) { result, err := allocationcandidates.ExtractAllocationCandidates110(page) th.AssertNoErr(t, err) - th.AssertEquals(t, true, len(result.AllocationRequests) > 0) - th.AssertEquals(t, true, len(result.ProviderSummaries) > 0) + th.AssertTrue(t, len(result.AllocationRequests) > 0) + th.AssertTrue(t, len(result.ProviderSummaries) > 0) // Assert: UUID of the created RP present and resource amount correct. var foundAlloc allocationcandidates.AllocationRequest110Resource @@ -181,9 +181,9 @@ func TestAllocationCandidatesList110(t *testing.T) { // Assert: The provider summary contains the expected inventory. rpSummary, present := result.ProviderSummaries[rpUUID] - th.AssertEquals(t, true, present) + th.AssertTrue(t, present) vcpuSummary, present := rpSummary.Resources["VCPU"] - th.AssertEquals(t, true, present) + th.AssertTrue(t, present) th.AssertEquals(t, 8, vcpuSummary.Capacity) th.AssertEquals(t, 0, vcpuSummary.Used) } @@ -207,7 +207,7 @@ func TestAllocationCandidatesIsEmpty110(t *testing.T) { isEmpty, err := page.IsEmpty() th.AssertNoErr(t, err) - th.AssertEquals(t, false, isEmpty) + th.AssertFalse(t, isEmpty) } func TestAllocationCandidatesListEmpty(t *testing.T) { @@ -231,5 +231,5 @@ func TestAllocationCandidatesListEmpty(t *testing.T) { isEmpty, err := page.IsEmpty() th.AssertNoErr(t, err) - th.AssertEquals(t, true, isEmpty) + th.AssertTrue(t, isEmpty) } diff --git a/internal/acceptance/openstack/placement/v1/allocations_test.go b/internal/acceptance/openstack/placement/v1/allocations_test.go index bf95d0bc40..2c8d24ed05 100644 --- a/internal/acceptance/openstack/placement/v1/allocations_test.go +++ b/internal/acceptance/openstack/placement/v1/allocations_test.go @@ -159,7 +159,7 @@ func TestUpdateAllocationsConflict(t *testing.T) { UserID: "test-user", ConsumerGeneration: &staleGeneration, }).ExtractErr() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusConflict)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusConflict)) } func TestDeleteAllocationsSuccess(t *testing.T) { @@ -212,7 +212,7 @@ func TestDeleteAllocationsNotFound(t *testing.T) { // Assert: An RP that was never a consumer returns 404 on DELETE. err = allocations.Delete(context.TODO(), client, resourceProvider.UUID).ExtractErr() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } func TestManageAllocationsSuccess(t *testing.T) { diff --git a/internal/acceptance/openstack/placement/v1/resourceclasses_test.go b/internal/acceptance/openstack/placement/v1/resourceclasses_test.go index 13f7663e40..c4e78cad9d 100644 --- a/internal/acceptance/openstack/placement/v1/resourceclasses_test.go +++ b/internal/acceptance/openstack/placement/v1/resourceclasses_test.go @@ -32,7 +32,7 @@ func TestResourceClassesList(t *testing.T) { th.AssertNoErr(t, err) // Ensure VCPU is in the list - th.AssertEquals(t, true, slices.ContainsFunc(allResourceClasses, func(rc resourceclasses.ResourceClass) bool { + th.AssertTrue(t, slices.ContainsFunc(allResourceClasses, func(rc resourceclasses.ResourceClass) bool { return rc.Name == "VCPU" })) } @@ -63,7 +63,7 @@ func TestResourceClassGetNegative(t *testing.T) { client.Microversion = "1.2" _, err = resourceclasses.Get(context.TODO(), client, "NON_EXISTENT_RC").Extract() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } func TestResourceClassCreateByPostSuccess(t *testing.T) { @@ -111,7 +111,7 @@ func TestResourceClassCreateByPostDuplicate(t *testing.T) { // Act: Try to create the same resource class again err = resourceclasses.Create(context.TODO(), client, createOpts).ExtractErr() // Assert: The error is a conflict - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusConflict)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusConflict)) } func TestResourceClassCreateByUpdateSuccess(t *testing.T) { @@ -155,7 +155,7 @@ func TestResourceClassCreateByUpdateNonCustomName(t *testing.T) { // Act: Try to create a resource class with a non-custom name using PUT (Update) err = resourceclasses.Update(context.TODO(), client, name).ExtractErr() // Assert: We get 400 - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) } func TestResourceClassDeleteSuccess(t *testing.T) { @@ -187,7 +187,7 @@ func TestResourceClassDeleteSuccess(t *testing.T) { // Assert: The resource class no longer exists _, err = resourceclasses.Get(context.TODO(), client, name).Extract() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } func TestResourceClassDeleteNotFound(t *testing.T) { @@ -202,7 +202,7 @@ func TestResourceClassDeleteNotFound(t *testing.T) { // Act: Try to delete a non-existent resource class err = resourceclasses.Delete(context.TODO(), client, "CUSTOM_NON_EXISTENT_RC").ExtractErr() // Assert: We get 404 - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } func TestResourceClassDeleteStandardClass(t *testing.T) { @@ -217,5 +217,5 @@ func TestResourceClassDeleteStandardClass(t *testing.T) { // Act: Try to delete a standard resource class err = resourceclasses.Delete(context.TODO(), client, "VCPU").ExtractErr() // Assert: We get 400 - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) } diff --git a/internal/acceptance/openstack/placement/v1/resourceproviders_test.go b/internal/acceptance/openstack/placement/v1/resourceproviders_test.go index cb471554c7..424e202e09 100644 --- a/internal/acceptance/openstack/placement/v1/resourceproviders_test.go +++ b/internal/acceptance/openstack/placement/v1/resourceproviders_test.go @@ -96,7 +96,7 @@ func TestResourceProviderList139(t *testing.T) { // Assert: Our resource provider is in the results and has the traits and aggregates we set. allResourceProviders, err := resourceproviders.ExtractResourceProviders(allPages) th.AssertNoErr(t, err) - th.AssertEquals(t, true, len(allResourceProviders) > 0) + th.AssertTrue(t, len(allResourceProviders) > 0) found := false for _, rp := range allResourceProviders { @@ -105,7 +105,7 @@ func TestResourceProviderList139(t *testing.T) { break } } - th.AssertEquals(t, true, found) + th.AssertTrue(t, found) } func TestResourceProvider(t *testing.T) { @@ -242,7 +242,7 @@ func TestResourceProviderInventoryNotFound(t *testing.T) { th.AssertNoErr(t, err) _, err = resourceproviders.GetInventory(context.TODO(), client, resourceProvider.UUID, MissingInventoryResourceClass).Extract() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } func TestResourceProviderUpdateInventory(t *testing.T) { @@ -304,7 +304,7 @@ func TestResourceProviderUpdateInventory(t *testing.T) { th.AssertNoErr(t, err) actualInventory, ok := updatedInventories.Inventories[InventoryResourceClass] - th.AssertEquals(t, true, ok) + th.AssertTrue(t, ok) th.AssertDeepEquals(t, expectedInventory, actualInventory) } @@ -327,7 +327,7 @@ func TestResourceProviderUpdateInventoryNotFound(t *testing.T) { } _, err = resourceproviders.UpdateInventory(context.TODO(), client, tools.RandomUUID(), InventoryResourceClass, updateOpts).Extract() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } func TestResourceProviderDeleteInventorySuccess(t *testing.T) { @@ -367,7 +367,7 @@ func TestResourceProviderDeleteInventorySuccess(t *testing.T) { th.AssertNoErr(t, err) _, found := updatedInventories.Inventories[InventoryResourceClass] - th.AssertEquals(t, false, found) + th.AssertFalse(t, found) } func TestResourceProviderDeleteInventoryNotFound(t *testing.T) { @@ -381,7 +381,7 @@ func TestResourceProviderDeleteInventoryNotFound(t *testing.T) { defer DeleteResourceProvider(t, client, resourceProvider.UUID) err = resourceproviders.DeleteInventory(context.TODO(), client, resourceProvider.UUID, MissingInventoryResourceClass).ExtractErr() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } func TestResourceProviderDeleteInventoriesSuccess(t *testing.T) { @@ -503,7 +503,7 @@ func TestResourceProviderUpdateInventoriesNotFound(t *testing.T) { } _, err = resourceproviders.UpdateInventories(context.TODO(), client, tools.RandomUUID(), updateOpts).Extract() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } func TestResourceProviderTraits(t *testing.T) { @@ -560,7 +560,7 @@ func TestResourceProviderAggregates(t *testing.T) { client.Microversion = "1.19" aggregates, err := resourceproviders.GetAggregates(context.TODO(), client, resourceProvider.UUID).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, true, aggregates.ResourceProviderGeneration != nil) + th.AssertTrue(t, aggregates.ResourceProviderGeneration != nil) // ensure that we handle older microversions where generation is missing client.Microversion = "1.1" @@ -579,11 +579,11 @@ func TestResourceProviderAggregatesNotFound(t *testing.T) { client.Microversion = "1.19" _, err = resourceproviders.GetAggregates(context.TODO(), client, tools.RandomUUID()).Extract() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) client.Microversion = "1.1" _, err = resourceproviders.GetAggregates(context.TODO(), client, tools.RandomUUID()).Extract() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } func TestResourceProviderUpdateAggregates(t *testing.T) { @@ -601,7 +601,7 @@ func TestResourceProviderUpdateAggregates(t *testing.T) { before, err := resourceproviders.GetAggregates(context.TODO(), client, resourceProvider.UUID).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, true, before.ResourceProviderGeneration != nil) + th.AssertTrue(t, before.ResourceProviderGeneration != nil) updateOpts := resourceproviders.UpdateAggregatesOpts{ ResourceProviderGeneration: before.ResourceProviderGeneration, @@ -619,7 +619,7 @@ func TestResourceProviderUpdateAggregates(t *testing.T) { th.AssertEquals(t, len(updateOpts.Aggregates), len(after.Aggregates)) for _, aggregate := range updateOpts.Aggregates { - th.AssertEquals(t, true, slices.Contains(after.Aggregates, aggregate)) + th.AssertTrue(t, slices.Contains(after.Aggregates, aggregate)) } } @@ -638,7 +638,7 @@ func TestResourceProviderUpdateAggregateMismatch(t *testing.T) { current, err := resourceproviders.GetAggregates(context.TODO(), client, resourceProvider.UUID).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, true, current.ResourceProviderGeneration != nil) + th.AssertTrue(t, current.ResourceProviderGeneration != nil) wrongGeneration := *current.ResourceProviderGeneration + 100 updateOpts := resourceproviders.UpdateAggregatesOpts{ @@ -649,7 +649,7 @@ func TestResourceProviderUpdateAggregateMismatch(t *testing.T) { } _, err = resourceproviders.UpdateAggregates(context.TODO(), client, resourceProvider.UUID, updateOpts).Extract() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusConflict)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusConflict)) } func TestResourceProviderUpdateAggregatesPreGeneration(t *testing.T) { @@ -680,7 +680,7 @@ func TestResourceProviderUpdateAggregatesPreGeneration(t *testing.T) { th.AssertEquals(t, len(updateOpts.Aggregates), len(after.Aggregates)) for _, aggregate := range updateOpts.Aggregates { - th.AssertEquals(t, true, slices.Contains(after.Aggregates, aggregate)) + th.AssertTrue(t, slices.Contains(after.Aggregates, aggregate)) } } @@ -716,7 +716,7 @@ func TestResourceProviderUpdateAggregatesPreGenerationWithGenerationSuccess(t *t th.AssertEquals(t, len(updateOpts.Aggregates), len(after.Aggregates)) for _, aggregate := range updateOpts.Aggregates { - th.AssertEquals(t, true, slices.Contains(after.Aggregates, aggregate)) + th.AssertTrue(t, slices.Contains(after.Aggregates, aggregate)) } } diff --git a/internal/acceptance/openstack/placement/v1/traits_test.go b/internal/acceptance/openstack/placement/v1/traits_test.go index 0bea5ef944..5b56fafaa1 100644 --- a/internal/acceptance/openstack/placement/v1/traits_test.go +++ b/internal/acceptance/openstack/placement/v1/traits_test.go @@ -33,7 +33,7 @@ func TestTraitsList(t *testing.T) { // Ensure COMPUTE_NODE is in the list // os-traits never removes traits, so this should always pass - th.AssertEquals(t, true, slices.Contains(allTraits, "COMPUTE_NODE")) + th.AssertTrue(t, slices.Contains(allTraits, "COMPUTE_NODE")) } func TestTraitGet(t *testing.T) { @@ -62,7 +62,7 @@ func TestTraitGetNegative(t *testing.T) { // Verify that Get returns an error for a non-existent trait err = traits.Get(context.TODO(), client, "CUSTOM_NON_EXISTENT_TRAIT").ExtractErr() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } func TestTraitsListFiltering(t *testing.T) { @@ -86,7 +86,7 @@ func TestTraitsListFiltering(t *testing.T) { th.AssertNoErr(t, err) for _, trait := range filteredTraits { - th.AssertEquals(t, true, strings.HasPrefix(trait, "HW_")) + th.AssertTrue(t, strings.HasPrefix(trait, "HW_")) } } @@ -142,7 +142,7 @@ func TestTraitsCreateInvalidName(t *testing.T) { traitName := "HW_WE_CANNOT_CREATE_THIS_TRAIT" err = traits.Create(context.TODO(), client, traitName).ExtractErr() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) } func TestTraitsDeleteSuccess(t *testing.T) { @@ -166,7 +166,7 @@ func TestTraitsDeleteSuccess(t *testing.T) { // Assert: The trait no longer exists err = traits.Get(context.TODO(), client, traitName).ExtractErr() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } func TestTraitsDeleteNotFound(t *testing.T) { @@ -181,7 +181,7 @@ func TestTraitsDeleteNotFound(t *testing.T) { traitName := strings.ToUpper(tools.RandomString("CUSTOM_", 8)) err = traits.Delete(context.TODO(), client, traitName).ExtractErr() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } // API does allow manipulation solely of custom traits, @@ -198,5 +198,5 @@ func TestTraitsDeleteStandardTraitFailure(t *testing.T) { traitName := "COMPUTE_NODE" err = traits.Delete(context.TODO(), client, traitName).ExtractErr() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) } diff --git a/internal/acceptance/openstack/sharedfilesystems/v2/sharetransfers_test.go b/internal/acceptance/openstack/sharedfilesystems/v2/sharetransfers_test.go index 41601621ca..6deac825fb 100644 --- a/internal/acceptance/openstack/sharedfilesystems/v2/sharetransfers_test.go +++ b/internal/acceptance/openstack/sharedfilesystems/v2/sharetransfers_test.go @@ -53,13 +53,13 @@ func TestTransferRequestCRUD(t *testing.T) { foundRequest = true } } - th.AssertEquals(t, true, foundRequest) + th.AssertTrue(t, foundRequest) // checking get tr, err := sharetransfers.Get(context.TODO(), client, transferRequest.ID).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, true, transferRequest.ID == tr.ID) + th.AssertTrue(t, transferRequest.ID == tr.ID) // Accept Share Transfer Request err = AcceptTransfer(t, client, transferRequest) diff --git a/openstack/baremetal/v1/conductors/testing/requests_test.go b/openstack/baremetal/v1/conductors/testing/requests_test.go index b85a9d77fb..d0463fd79d 100644 --- a/openstack/baremetal/v1/conductors/testing/requests_test.go +++ b/openstack/baremetal/v1/conductors/testing/requests_test.go @@ -58,9 +58,9 @@ func TestListDetailConductors(t *testing.T) { t.Fatalf("Expected 2 conductors, got %d", len(actual)) } th.AssertEquals(t, "compute1.localdomain", actual[0].Hostname) - th.AssertEquals(t, false, actual[0].Alive) + th.AssertFalse(t, actual[0].Alive) th.AssertEquals(t, "compute2.localdomain", actual[1].Hostname) - th.AssertEquals(t, true, actual[1].Alive) + th.AssertTrue(t, actual[1].Alive) return true, nil }) diff --git a/openstack/blockstorage/v3/volumetypes/testing/requests_test.go b/openstack/blockstorage/v3/volumetypes/testing/requests_test.go index c3410c0420..aa19f08e2e 100644 --- a/openstack/blockstorage/v3/volumetypes/testing/requests_test.go +++ b/openstack/blockstorage/v3/volumetypes/testing/requests_test.go @@ -64,7 +64,7 @@ func TestGet(t *testing.T) { th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", v.ID) th.AssertEquals(t, "gpu", v.ExtraSpecs["capabilities"]) th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", v.QosSpecID) - th.AssertEquals(t, true, v.PublicAccess) + th.AssertTrue(t, v.PublicAccess) } func TestCreate(t *testing.T) { @@ -87,8 +87,8 @@ func TestCreate(t *testing.T) { th.AssertEquals(t, "test_type", n.Name) th.AssertEquals(t, "test_type_desc", n.Description) - th.AssertEquals(t, true, n.IsPublic) - th.AssertEquals(t, true, n.PublicAccess) + th.AssertTrue(t, n.IsPublic) + th.AssertTrue(t, n.PublicAccess) th.AssertEquals(t, "6d0ff92a-0007-4780-9ece-acfe5876966a", n.ID) th.AssertEquals(t, "gpu", n.ExtraSpecs["capabilities"]) } @@ -119,7 +119,7 @@ func TestUpdate(t *testing.T) { v, err := volumetypes.Update(context.TODO(), client.ServiceClient(fakeServer), "d32019d3-bc6e-4319-9c1d-6722fc136a22", options).Extract() th.AssertNoErr(t, err) th.CheckEquals(t, "vol-type-002", v.Name) - th.CheckEquals(t, true, v.IsPublic) + th.CheckTrue(t, v.IsPublic) } func TestListIsPublicParam(t *testing.T) { @@ -180,8 +180,8 @@ func TestListNameParam(t *testing.T) { th.AssertEquals(t, "test-type", actual[0].Name) th.AssertEquals(t, "996af3df-92fd-4814-a0ee-ba5f899aa1ec", actual[0].ID) th.AssertEquals(t, "test", actual[0].Description) - th.AssertEquals(t, true, actual[0].IsPublic) - th.AssertEquals(t, true, actual[0].PublicAccess) + th.AssertTrue(t, actual[0].IsPublic) + th.AssertTrue(t, actual[0].PublicAccess) th.AssertEquals(t, "nfs", actual[0].ExtraSpecs["storage_protocol"]) } @@ -203,8 +203,8 @@ func TestListDescriptionParam(t *testing.T) { th.AssertEquals(t, "test", actual[0].Description) th.AssertEquals(t, "test-type", actual[0].Name) th.AssertEquals(t, "ab948f0a-13ed-47c8-b9be-cade0beb0706", actual[0].ID) - th.AssertEquals(t, true, actual[0].IsPublic) - th.AssertEquals(t, true, actual[0].PublicAccess) + th.AssertTrue(t, actual[0].IsPublic) + th.AssertTrue(t, actual[0].PublicAccess) th.AssertEquals(t, " True", actual[0].ExtraSpecs["multiattach"]) } @@ -432,7 +432,7 @@ func TestGetEncryption(t *testing.T) { th.AssertEquals(t, "a5082c24-2a27-43a4-b48e-fcec1240e36b", n.VolumeTypeID) th.AssertEquals(t, "front-end", n.ControlLocation) - th.AssertEquals(t, false, n.Deleted) + th.AssertFalse(t, n.Deleted) th.AssertEquals(t, "2016-12-28T02:32:25.000000", n.CreatedAt) th.AssertEquals(t, "", n.UpdatedAt) th.AssertEquals(t, "81e069c6-7394-4856-8df7-3b237ca61f74", n.EncryptionID) diff --git a/openstack/compute/v2/tags/testing/requests_test.go b/openstack/compute/v2/tags/testing/requests_test.go index fa93b49485..9f0c344c5b 100644 --- a/openstack/compute/v2/tags/testing/requests_test.go +++ b/openstack/compute/v2/tags/testing/requests_test.go @@ -47,7 +47,7 @@ func TestCheckOk(t *testing.T) { exists, err := tags.Check(context.TODO(), client.ServiceClient(fakeServer), "uuid1", "foo").Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, true, exists) + th.AssertTrue(t, exists) } func TestCheckFail(t *testing.T) { @@ -64,7 +64,7 @@ func TestCheckFail(t *testing.T) { exists, err := tags.Check(context.TODO(), client.ServiceClient(fakeServer), "uuid1", "bar").Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, false, exists) + th.AssertFalse(t, exists) } func TestReplaceAll(t *testing.T) { diff --git a/openstack/containerinfra/v1/clustertemplates/testing/requests_test.go b/openstack/containerinfra/v1/clustertemplates/testing/requests_test.go index 4e7058dc14..03e5c1e05b 100644 --- a/openstack/containerinfra/v1/clustertemplates/testing/requests_test.go +++ b/openstack/containerinfra/v1/clustertemplates/testing/requests_test.go @@ -211,5 +211,5 @@ func TestUpdateClusterTemplateInvalidUpdate(t *testing.T) { sc := client.ServiceClient(fakeServer) sc.Endpoint = sc.Endpoint + "v1/" _, err := clustertemplates.Update(context.TODO(), sc, "7d85f602-a948-4a30-afd4-e84f47471c15", updateOpts).Extract() - th.AssertEquals(t, true, err != nil) + th.AssertTrue(t, err != nil) } diff --git a/openstack/containerinfra/v1/nodegroups/testing/requests_test.go b/openstack/containerinfra/v1/nodegroups/testing/requests_test.go index 0964e23b3d..d8429fe8bf 100644 --- a/openstack/containerinfra/v1/nodegroups/testing/requests_test.go +++ b/openstack/containerinfra/v1/nodegroups/testing/requests_test.go @@ -38,7 +38,7 @@ func TestGetNodeGroupNotFound(t *testing.T) { sc.Endpoint = sc.Endpoint + "v1/" _, err := nodegroups.Get(context.TODO(), sc, clusterUUID, badNodeGroupUUID).Extract() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } // TestGetNodeGroupClusterNotFound tries to get a node group in @@ -53,7 +53,7 @@ func TestGetNodeGroupClusterNotFound(t *testing.T) { sc.Endpoint = sc.Endpoint + "v1/" _, err := nodegroups.Get(context.TODO(), sc, badClusterUUID, badNodeGroupUUID).Extract() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } // TestListNodeGroupsSuccess lists the node groups of a cluster successfully. @@ -111,7 +111,7 @@ func TestListNodeGroupsClusterNotFound(t *testing.T) { sc.Endpoint = sc.Endpoint + "v1/" _, err := nodegroups.List(sc, clusterUUID, nodegroups.ListOpts{}).AllPages(context.TODO()) - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } // TestCreateNodeGroupSuccess creates a node group successfully. @@ -150,7 +150,7 @@ func TestCreateNodeGroupDuplicate(t *testing.T) { } _, err := nodegroups.Create(context.TODO(), sc, clusterUUID, createOpts).Extract() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusConflict)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusConflict)) } // TestCreateNodeGroupMaster creates a node group with @@ -170,7 +170,7 @@ func TestCreateNodeGroupMaster(t *testing.T) { } _, err := nodegroups.Create(context.TODO(), sc, clusterUUID, createOpts).Extract() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) } // TestCreateNodeGroupBadSizes creates a node group with @@ -192,7 +192,7 @@ func TestCreateNodeGroupBadSizes(t *testing.T) { } _, err := nodegroups.Create(context.TODO(), sc, clusterUUID, createOpts).Extract() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusConflict)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusConflict)) } // TestUpdateNodeGroupSuccess updates a node group successfully. @@ -238,7 +238,7 @@ func TestUpdateNodeGroupInternal(t *testing.T) { } _, err := nodegroups.Update(context.TODO(), sc, clusterUUID, nodeGroup2UUID, updateOpts).Extract() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) } // TestUpdateNodeGroupBadField tries to update a @@ -261,7 +261,7 @@ func TestUpdateNodeGroupBadField(t *testing.T) { } _, err := nodegroups.Update(context.TODO(), sc, clusterUUID, nodeGroup2UUID, updateOpts).Extract() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) } // TestUpdateNodeGroupBadMin tries to set a minimum node count @@ -284,7 +284,7 @@ func TestUpdateNodeGroupBadMin(t *testing.T) { } _, err := nodegroups.Update(context.TODO(), sc, clusterUUID, nodeGroup2UUID, updateOpts).Extract() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusConflict)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusConflict)) } // TestDeleteNodeGroupSuccess deletes a node group successfully. @@ -312,7 +312,7 @@ func TestDeleteNodeGroupNotFound(t *testing.T) { sc.Endpoint = sc.Endpoint + "v1/" err := nodegroups.Delete(context.TODO(), sc, clusterUUID, badNodeGroupUUID).ExtractErr() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } // TestDeleteNodeGroupClusterNotFound tries to delete a node group in a cluster that does not exist. @@ -326,7 +326,7 @@ func TestDeleteNodeGroupClusterNotFound(t *testing.T) { sc.Endpoint = sc.Endpoint + "v1/" err := nodegroups.Delete(context.TODO(), sc, badClusterUUID, badNodeGroupUUID).ExtractErr() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } // TestDeleteNodeGroupDefault tries to delete a protected default node group. @@ -340,5 +340,5 @@ func TestDeleteNodeGroupDefault(t *testing.T) { sc.Endpoint = sc.Endpoint + "v1/" err := nodegroups.Delete(context.TODO(), sc, clusterUUID, nodeGroup2UUID).ExtractErr() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) } diff --git a/openstack/db/v1/instances/testing/requests_test.go b/openstack/db/v1/instances/testing/requests_test.go index 8961bc1727..01eb9c6f71 100644 --- a/openstack/db/v1/instances/testing/requests_test.go +++ b/openstack/db/v1/instances/testing/requests_test.go @@ -166,7 +166,7 @@ func TestIsRootEnabled(t *testing.T) { isEnabled, err := instances.IsRootEnabled(context.TODO(), client.ServiceClient(fakeServer), instanceID).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, true, isEnabled) + th.AssertTrue(t, isEnabled) } func TestRestart(t *testing.T) { diff --git a/openstack/identity/v3/users/testing/requests_test.go b/openstack/identity/v3/users/testing/requests_test.go index 1754d283e9..5d2bafdda6 100644 --- a/openstack/identity/v3/users/testing/requests_test.go +++ b/openstack/identity/v3/users/testing/requests_test.go @@ -209,7 +209,7 @@ func TestIsMemberOfGroup(t *testing.T) { HandleIsMemberOfGroupSuccessfully(t, fakeServer) ok, err := users.IsMemberOfGroup(context.TODO(), client.ServiceClient(fakeServer), "ea167b", "9fe1d3").Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, true, ok) + th.AssertTrue(t, ok) } func TestRemoveFromGroup(t *testing.T) { diff --git a/openstack/networking/v2/extensions/agents/testing/requests_test.go b/openstack/networking/v2/extensions/agents/testing/requests_test.go index 9777578e33..c75e1a8106 100644 --- a/openstack/networking/v2/extensions/agents/testing/requests_test.go +++ b/openstack/networking/v2/extensions/agents/testing/requests_test.go @@ -74,8 +74,8 @@ func TestGet(t *testing.T) { th.AssertEquals(t, "43583cf5-472e-4dc8-af5b-6aed4c94ee3a", s.ID) th.AssertEquals(t, "neutron-openvswitch-agent", s.Binary) - th.AssertEquals(t, true, s.AdminStateUp) - th.AssertEquals(t, true, s.Alive) + th.AssertTrue(t, s.AdminStateUp) + th.AssertTrue(t, s.Alive) th.AssertEquals(t, "N/A", s.Topic) th.AssertEquals(t, "compute3", s.Host) th.AssertEquals(t, "Open vSwitch agent", s.AgentType) @@ -158,9 +158,9 @@ func TestListDHCPNetworks(t *testing.T) { var nilSlice []string th.AssertEquals(t, 1, len(s)) th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", s[0].ID) - th.AssertEquals(t, true, s[0].AdminStateUp) + th.AssertTrue(t, s[0].AdminStateUp) th.AssertEquals(t, "4fd44f30292945e481c7b8a0c8908869", s[0].ProjectID) - th.AssertEquals(t, false, s[0].Shared) + th.AssertFalse(t, s[0].Shared) th.AssertEquals(t, "net1", s[0].Name) th.AssertEquals(t, "ACTIVE", s[0].Status) th.AssertDeepEquals(t, s[0].Tags, nilSlice) @@ -375,7 +375,7 @@ func TestListL3Routers(t *testing.T) { var nilSlice []string th.AssertEquals(t, 2, len(s)) th.AssertEquals(t, "915a14a6-867b-4af7-83d1-70efceb146f9", s[0].ID) - th.AssertEquals(t, true, s[0].AdminStateUp) + th.AssertTrue(t, s[0].AdminStateUp) th.AssertEquals(t, "0bd18306d801447bb457a46252d82d13", s[0].ProjectID) th.AssertEquals(t, "router2", s[0].Name) th.AssertEquals(t, "ACTIVE", s[0].Status) diff --git a/openstack/networking/v2/extensions/attributestags/testing/requests_test.go b/openstack/networking/v2/extensions/attributestags/testing/requests_test.go index dfeab5abd5..7158693d02 100644 --- a/openstack/networking/v2/extensions/attributestags/testing/requests_test.go +++ b/openstack/networking/v2/extensions/attributestags/testing/requests_test.go @@ -119,7 +119,7 @@ func TestConfirmTrue(t *testing.T) { exists, err := attributestags.Confirm(context.TODO(), fake.ServiceClient(fakeServer), "networks", "fakeid", "atag").Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, true, exists) + th.AssertTrue(t, exists) } func TestConfirmFalse(t *testing.T) { @@ -135,5 +135,5 @@ func TestConfirmFalse(t *testing.T) { }) exists, _ := attributestags.Confirm(context.TODO(), fake.ServiceClient(fakeServer), "networks", "fakeid", "atag").Extract() - th.AssertEquals(t, false, exists) + th.AssertFalse(t, exists) } diff --git a/openstack/networking/v2/extensions/dns/testing/requests_test.go b/openstack/networking/v2/extensions/dns/testing/requests_test.go index e713bb7b63..55e9b1664b 100644 --- a/openstack/networking/v2/extensions/dns/testing/requests_test.go +++ b/openstack/networking/v2/extensions/dns/testing/requests_test.go @@ -101,7 +101,7 @@ func TestPortGet(t *testing.T) { th.AssertEquals(t, "ACTIVE", s.Status) th.AssertEquals(t, "", s.Name) - th.AssertEquals(t, true, s.AdminStateUp) + th.AssertTrue(t, s.AdminStateUp) th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", s.NetworkID) th.AssertEquals(t, "7e02058126cc4950b75f9970368ba177", s.TenantID) th.AssertEquals(t, "network:router_interface", s.DeviceOwner) @@ -152,7 +152,7 @@ func TestPortCreate(t *testing.T) { th.AssertEquals(t, "DOWN", s.Status) th.AssertEquals(t, "private-port", s.Name) - th.AssertEquals(t, true, s.AdminStateUp) + th.AssertTrue(t, s.AdminStateUp) th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", s.NetworkID) th.AssertEquals(t, "d6700c0c9ffa4f1cb322cd4a1f3906fa", s.TenantID) th.AssertEquals(t, "", s.DeviceOwner) diff --git a/openstack/networking/v2/extensions/external/testing/results_test.go b/openstack/networking/v2/extensions/external/testing/results_test.go index 8de68e70e5..e0701a0e1e 100644 --- a/openstack/networking/v2/extensions/external/testing/results_test.go +++ b/openstack/networking/v2/extensions/external/testing/results_test.go @@ -40,7 +40,7 @@ func TestList(t *testing.T) { th.AssertNoErr(t, err) th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", actual[0].ID) - th.AssertEquals(t, true, actual[0].External) + th.AssertTrue(t, actual[0].External) } func TestGet(t *testing.T) { @@ -66,7 +66,7 @@ func TestGet(t *testing.T) { th.AssertNoErr(t, err) th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", s.ID) - th.AssertEquals(t, true, s.External) + th.AssertTrue(t, s.External) } func TestCreate(t *testing.T) { diff --git a/openstack/networking/v2/extensions/fwaas_v2/groups/testing/requests_test.go b/openstack/networking/v2/extensions/fwaas_v2/groups/testing/requests_test.go index 54c5c6c230..fabed6d4be 100644 --- a/openstack/networking/v2/extensions/fwaas_v2/groups/testing/requests_test.go +++ b/openstack/networking/v2/extensions/fwaas_v2/groups/testing/requests_test.go @@ -166,11 +166,11 @@ func TestGet(t *testing.T) { th.AssertEquals(t, "some information", group.Description) th.AssertEquals(t, "e3f11142-3792-454b-8d3e-91ac1bf127b4", group.IngressFirewallPolicyID) th.AssertEquals(t, "", group.EgressFirewallPolicyID) - th.AssertEquals(t, true, group.AdminStateUp) + th.AssertTrue(t, group.AdminStateUp) th.AssertEquals(t, 1, len(group.Ports)) th.AssertEquals(t, "a6af1e56-b12b-4733-8f77-49166afd5719", group.Ports[0]) th.AssertEquals(t, "ACTIVE", group.Status) - th.AssertEquals(t, false, group.Shared) + th.AssertFalse(t, group.Shared) th.AssertEquals(t, "9f98fc0e5f944cd1b51798b668dc8778", group.TenantID) } diff --git a/openstack/networking/v2/extensions/fwaas_v2/rules/testing/requests_test.go b/openstack/networking/v2/extensions/fwaas_v2/rules/testing/requests_test.go index 78419e4b81..4f9ce33792 100644 --- a/openstack/networking/v2/extensions/fwaas_v2/rules/testing/requests_test.go +++ b/openstack/networking/v2/extensions/fwaas_v2/rules/testing/requests_test.go @@ -301,10 +301,10 @@ func TestGet(t *testing.T) { th.AssertEquals(t, "ssh_form_any", rule.Name) th.AssertEquals(t, "80cf934d6ffb4ef5b244f1c512ad1e61", rule.TenantID) th.AssertEquals(t, "80cf934d6ffb4ef5b244f1c512ad1e61", rule.ProjectID) - th.AssertEquals(t, true, rule.Enabled) + th.AssertTrue(t, rule.Enabled) th.AssertEquals(t, "allow", rule.Action) th.AssertEquals(t, 4, rule.IPVersion) - th.AssertEquals(t, false, rule.Shared) + th.AssertFalse(t, rule.Shared) } func TestUpdate(t *testing.T) { diff --git a/openstack/networking/v2/extensions/layer3/addressscopes/testing/requests_test.go b/openstack/networking/v2/extensions/layer3/addressscopes/testing/requests_test.go index 2e1e8eaf46..f8bb9108ae 100644 --- a/openstack/networking/v2/extensions/layer3/addressscopes/testing/requests_test.go +++ b/openstack/networking/v2/extensions/layer3/addressscopes/testing/requests_test.go @@ -74,7 +74,7 @@ func TestGet(t *testing.T) { th.AssertEquals(t, "4a9807b773404e979b19633f38370643", s.TenantID) th.AssertEquals(t, "4a9807b773404e979b19633f38370643", s.ProjectID) th.AssertEquals(t, 4, s.IPVersion) - th.AssertEquals(t, false, s.Shared) + th.AssertFalse(t, s.Shared) } func TestCreate(t *testing.T) { @@ -103,7 +103,7 @@ func TestCreate(t *testing.T) { th.AssertNoErr(t, err) th.AssertEquals(t, "test0", s.Name) - th.AssertEquals(t, true, s.Shared) + th.AssertTrue(t, s.Shared) th.AssertEquals(t, 4, s.IPVersion) th.AssertEquals(t, "4a9807b773404e979b19633f38370643", s.TenantID) th.AssertEquals(t, "4a9807b773404e979b19633f38370643", s.ProjectID) @@ -137,7 +137,7 @@ func TestUpdate(t *testing.T) { th.AssertNoErr(t, err) th.AssertEquals(t, "test1", s.Name) - th.AssertEquals(t, true, s.Shared) + th.AssertTrue(t, s.Shared) } func TestDelete(t *testing.T) { diff --git a/openstack/networking/v2/extensions/layer3/routers/testing/requests_test.go b/openstack/networking/v2/extensions/layer3/routers/testing/requests_test.go index 9404e24d02..1d3eb13444 100644 --- a/openstack/networking/v2/extensions/layer3/routers/testing/requests_test.go +++ b/openstack/networking/v2/extensions/layer3/routers/testing/requests_test.go @@ -216,7 +216,7 @@ func TestCreate(t *testing.T) { }} th.AssertEquals(t, "foo_router", r.Name) - th.AssertEquals(t, false, r.AdminStateUp) + th.AssertFalse(t, r.AdminStateUp) th.AssertDeepEquals(t, gwi, r.GatewayInfo) th.AssertDeepEquals(t, []string{"zone1", "zone2"}, r.AvailabilityZoneHints) } @@ -272,7 +272,7 @@ func TestGet(t *testing.T) { QoSPolicyID: "6601bae5-f15a-4687-8be9-ddec9a2f8a8b", }, n.GatewayInfo) th.AssertEquals(t, "router1", n.Name) - th.AssertEquals(t, true, n.AdminStateUp) + th.AssertTrue(t, n.AdminStateUp) th.AssertEquals(t, "d6554fe62e2f41efbb6e026fad5c1542", n.TenantID) th.AssertEquals(t, "a07eea83-7710-4860-931b-5fe220fae533", n.ID) th.AssertDeepEquals(t, []routers.Route{{DestinationCIDR: "40.0.1.0/24", NextHop: "10.1.0.10"}}, n.Routes) @@ -833,7 +833,7 @@ func TestUpdateExternalGateways(t *testing.T) { th.AssertEquals(t, "router1", n.Name) th.AssertEquals(t, "4e8e5957-649f-477b-9e5b-f1f75b21c03c", n.ID) - th.AssertEquals(t, true, *n.GatewayInfo.EnableSNAT) + th.AssertTrue(t, *n.GatewayInfo.EnableSNAT) } func TestRemoveExternalGateways(t *testing.T) { diff --git a/openstack/networking/v2/extensions/portsbinding/testing/requests_test.go b/openstack/networking/v2/extensions/portsbinding/testing/requests_test.go index e973afdf01..9efd2f22a7 100644 --- a/openstack/networking/v2/extensions/portsbinding/testing/requests_test.go +++ b/openstack/networking/v2/extensions/portsbinding/testing/requests_test.go @@ -77,7 +77,7 @@ func TestGet(t *testing.T) { th.AssertEquals(t, "ACTIVE", s.Status) th.AssertEquals(t, "", s.Name) - th.AssertEquals(t, true, s.AdminStateUp) + th.AssertTrue(t, s.AdminStateUp) th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", s.NetworkID) th.AssertEquals(t, "7e02058126cc4950b75f9970368ba177", s.TenantID) th.AssertEquals(t, "network:router_interface", s.DeviceOwner) @@ -128,7 +128,7 @@ func TestCreate(t *testing.T) { th.AssertEquals(t, "DOWN", s.Status) th.AssertEquals(t, "private-port", s.Name) - th.AssertEquals(t, true, s.AdminStateUp) + th.AssertTrue(t, s.AdminStateUp) th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", s.NetworkID) th.AssertEquals(t, "d6700c0c9ffa4f1cb322cd4a1f3906fa", s.TenantID) th.AssertEquals(t, "", s.DeviceOwner) diff --git a/openstack/networking/v2/extensions/portstrustedvif/testing/requests_test.go b/openstack/networking/v2/extensions/portstrustedvif/testing/requests_test.go index 47ecdc7db5..a8a0e1966f 100644 --- a/openstack/networking/v2/extensions/portstrustedvif/testing/requests_test.go +++ b/openstack/networking/v2/extensions/portstrustedvif/testing/requests_test.go @@ -95,7 +95,7 @@ func TestGet(t *testing.T) { th.AssertEquals(t, "DOWN", s.Status) th.AssertEquals(t, "private-port", s.Name) - th.AssertEquals(t, true, s.AdminStateUp) + th.AssertTrue(t, s.AdminStateUp) th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", s.NetworkID) th.AssertEquals(t, "d6700c0c9ffa4f1cb322cd4a1f3906fa", s.TenantID) th.AssertEquals(t, "", s.DeviceOwner) @@ -109,7 +109,7 @@ func TestGet(t *testing.T) { if s.PortTrustedVIF == nil { t.Fatalf("Expected s.PortTrustedVIF to be not nil") } - th.AssertEquals(t, false, *s.PortTrustedVIF) + th.AssertFalse(t, *s.PortTrustedVIF) } func TestGetUnset(t *testing.T) { @@ -136,7 +136,7 @@ func TestGetUnset(t *testing.T) { th.AssertEquals(t, "DOWN", s.Status) th.AssertEquals(t, "private-port", s.Name) - th.AssertEquals(t, true, s.AdminStateUp) + th.AssertTrue(t, s.AdminStateUp) th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", s.NetworkID) th.AssertEquals(t, "d6700c0c9ffa4f1cb322cd4a1f3906fa", s.TenantID) th.AssertEquals(t, "", s.DeviceOwner) @@ -193,7 +193,7 @@ func TestCreateWithPortTrustedVIF(t *testing.T) { th.AssertEquals(t, "DOWN", portWithExt.Status) th.AssertEquals(t, "private-port", portWithExt.Name) - th.AssertEquals(t, true, portWithExt.AdminStateUp) + th.AssertTrue(t, portWithExt.AdminStateUp) th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", portWithExt.NetworkID) th.AssertEquals(t, "d6700c0c9ffa4f1cb322cd4a1f3906fa", portWithExt.TenantID) th.AssertEquals(t, "", portWithExt.DeviceOwner) @@ -202,7 +202,7 @@ func TestCreateWithPortTrustedVIF(t *testing.T) { {SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.2"}, }, portWithExt.FixedIPs) th.AssertEquals(t, "65c0ee9f-d634-4522-8954-51021b570b0d", portWithExt.ID) - th.AssertEquals(t, true, *portWithExt.PortTrustedVIF) + th.AssertTrue(t, *portWithExt.PortTrustedVIF) } func TestUpdatePortTrustedVIF(t *testing.T) { diff --git a/openstack/networking/v2/extensions/qos/policies/testing/requests_test.go b/openstack/networking/v2/extensions/qos/policies/testing/requests_test.go index 04394bcc97..767babf95d 100644 --- a/openstack/networking/v2/extensions/qos/policies/testing/requests_test.go +++ b/openstack/networking/v2/extensions/qos/policies/testing/requests_test.go @@ -400,8 +400,8 @@ func TestCreatePolicy(t *testing.T) { th.AssertNoErr(t, err) th.AssertEquals(t, "shared-default-policy", p.Name) - th.AssertEquals(t, true, p.Shared) - th.AssertEquals(t, true, p.IsDefault) + th.AssertTrue(t, p.Shared) + th.AssertTrue(t, p.IsDefault) th.AssertEquals(t, "use-me", p.Description) th.AssertEquals(t, "a77cbe0998374aed9a6798ad6c61677e", p.TenantID) th.AssertEquals(t, "a77cbe0998374aed9a6798ad6c61677e", p.ProjectID) @@ -439,8 +439,8 @@ func TestUpdatePolicy(t *testing.T) { th.AssertNoErr(t, err) th.AssertEquals(t, "new-name", p.Name) - th.AssertEquals(t, true, p.Shared) - th.AssertEquals(t, false, p.IsDefault) + th.AssertTrue(t, p.Shared) + th.AssertFalse(t, p.IsDefault) th.AssertEquals(t, "", p.Description) th.AssertEquals(t, "a77cbe0998374aed9a6798ad6c61677e", p.TenantID) th.AssertEquals(t, "a77cbe0998374aed9a6798ad6c61677e", p.ProjectID) diff --git a/openstack/networking/v2/extensions/subnetpools/testing/requests_test.go b/openstack/networking/v2/extensions/subnetpools/testing/requests_test.go index 7089f74726..f13ef69ca2 100644 --- a/openstack/networking/v2/extensions/subnetpools/testing/requests_test.go +++ b/openstack/networking/v2/extensions/subnetpools/testing/requests_test.go @@ -87,9 +87,9 @@ func TestGet(t *testing.T) { th.AssertEquals(t, 128, s.MaxPrefixLen) th.AssertEquals(t, "", s.AddressScopeID) th.AssertEquals(t, 6, s.IPversion) - th.AssertEquals(t, false, s.Shared) + th.AssertFalse(t, s.Shared) th.AssertEquals(t, "ipv6 prefixes", s.Description) - th.AssertEquals(t, true, s.IsDefault) + th.AssertTrue(t, s.IsDefault) th.AssertEquals(t, 2, s.RevisionNumber) } func TestCreate(t *testing.T) { diff --git a/openstack/networking/v2/extensions/vlantransparent/testing/requests_test.go b/openstack/networking/v2/extensions/vlantransparent/testing/requests_test.go index 1850f4db0a..834a8b8d5a 100644 --- a/openstack/networking/v2/extensions/vlantransparent/testing/requests_test.go +++ b/openstack/networking/v2/extensions/vlantransparent/testing/requests_test.go @@ -40,12 +40,12 @@ func TestList(t *testing.T) { th.AssertEquals(t, "db193ab3-96e3-4cb3-8fc5-05f4296d0324", actual[0].ID) th.AssertEquals(t, "private", actual[0].Name) - th.AssertEquals(t, true, actual[0].AdminStateUp) + th.AssertTrue(t, actual[0].AdminStateUp) th.AssertEquals(t, "ACTIVE", actual[0].Status) th.AssertDeepEquals(t, []string{"08eae331-0402-425a-923c-34f7cfe39c1b"}, actual[0].Subnets) th.AssertEquals(t, "26a7980765d0414dbc1fc1f88cdb7e6e", actual[0].TenantID) - th.AssertEquals(t, false, actual[0].Shared) - th.AssertEquals(t, true, actual[0].VLANTransparent) + th.AssertFalse(t, actual[0].Shared) + th.AssertTrue(t, actual[0].VLANTransparent) } func TestGet(t *testing.T) { @@ -72,12 +72,12 @@ func TestGet(t *testing.T) { th.AssertEquals(t, "db193ab3-96e3-4cb3-8fc5-05f4296d0324", s.ID) th.AssertEquals(t, "private", s.Name) - th.AssertEquals(t, true, s.AdminStateUp) + th.AssertTrue(t, s.AdminStateUp) th.AssertEquals(t, "ACTIVE", s.Status) th.AssertDeepEquals(t, []string{"08eae331-0402-425a-923c-34f7cfe39c1b"}, s.Subnets) th.AssertEquals(t, "26a7980765d0414dbc1fc1f88cdb7e6e", s.TenantID) - th.AssertEquals(t, false, s.Shared) - th.AssertEquals(t, true, s.VLANTransparent) + th.AssertFalse(t, s.Shared) + th.AssertTrue(t, s.VLANTransparent) } func TestCreate(t *testing.T) { @@ -117,12 +117,12 @@ func TestCreate(t *testing.T) { th.AssertEquals(t, "db193ab3-96e3-4cb3-8fc5-05f4296d0324", s.ID) th.AssertEquals(t, "private", s.Name) - th.AssertEquals(t, true, s.AdminStateUp) + th.AssertTrue(t, s.AdminStateUp) th.AssertEquals(t, "ACTIVE", s.Status) th.AssertDeepEquals(t, []string{"08eae331-0402-425a-923c-34f7cfe39c1b"}, s.Subnets) th.AssertEquals(t, "26a7980765d0414dbc1fc1f88cdb7e6e", s.TenantID) - th.AssertEquals(t, false, s.Shared) - th.AssertEquals(t, true, s.VLANTransparent) + th.AssertFalse(t, s.Shared) + th.AssertTrue(t, s.VLANTransparent) } func TestUpdate(t *testing.T) { @@ -164,10 +164,10 @@ func TestUpdate(t *testing.T) { th.AssertEquals(t, "db193ab3-96e3-4cb3-8fc5-05f4296d0324", s.ID) th.AssertEquals(t, "new_network_name", s.Name) - th.AssertEquals(t, false, s.AdminStateUp) + th.AssertFalse(t, s.AdminStateUp) th.AssertEquals(t, "ACTIVE", s.Status) th.AssertDeepEquals(t, []string{"08eae331-0402-425a-923c-34f7cfe39c1b"}, s.Subnets) th.AssertEquals(t, "26a7980765d0414dbc1fc1f88cdb7e6e", s.TenantID) - th.AssertEquals(t, false, s.Shared) - th.AssertEquals(t, false, s.VLANTransparent) + th.AssertFalse(t, s.Shared) + th.AssertFalse(t, s.VLANTransparent) } diff --git a/openstack/networking/v2/networks/testing/requests_test.go b/openstack/networking/v2/networks/testing/requests_test.go index 4d5bcc66d6..0e913d4a74 100644 --- a/openstack/networking/v2/networks/testing/requests_test.go +++ b/openstack/networking/v2/networks/testing/requests_test.go @@ -81,7 +81,7 @@ func TestListWithExtensions(t *testing.T) { th.AssertNoErr(t, err) th.AssertEquals(t, "ACTIVE", allNetworks[0].Status) - th.AssertEquals(t, true, allNetworks[0].PortSecurityEnabled) + th.AssertTrue(t, allNetworks[0].PortSecurityEnabled) th.AssertEquals(t, "54d6f61d-db07-451c-9ab3-b9609b6b6f0b", allNetworks[0].Subnets[0]) th.AssertEquals(t, "08eae331-0402-425a-923c-34f7cfe39c1b", allNetworks[1].Subnets[0]) th.AssertEquals(t, "2019-06-30T04:15:37Z", allNetworks[0].CreatedAt.Format(time.RFC3339)) @@ -134,7 +134,7 @@ func TestGetWithExtensions(t *testing.T) { th.AssertNoErr(t, err) th.AssertEquals(t, "ACTIVE", networkWithExtensions.Status) - th.AssertEquals(t, true, networkWithExtensions.PortSecurityEnabled) + th.AssertTrue(t, networkWithExtensions.PortSecurityEnabled) } func TestCreate(t *testing.T) { @@ -215,8 +215,8 @@ func TestUpdate(t *testing.T) { th.AssertNoErr(t, err) th.AssertEquals(t, "new_network_name", n.Name) - th.AssertEquals(t, false, n.AdminStateUp) - th.AssertEquals(t, true, n.Shared) + th.AssertFalse(t, n.AdminStateUp) + th.AssertTrue(t, n.Shared) th.AssertEquals(t, "4e8e5957-649f-477b-9e5b-f1f75b21c03c", n.ID) th.AssertEquals(t, "2019-06-30T04:15:37Z", n.CreatedAt.Format(time.RFC3339)) th.AssertEquals(t, "2019-06-30T05:18:49Z", n.UpdatedAt.Format(time.RFC3339)) @@ -313,7 +313,7 @@ func TestCreatePortSecurity(t *testing.T) { th.AssertNoErr(t, err) th.AssertEquals(t, "ACTIVE", networkWithExtensions.Status) - th.AssertEquals(t, false, networkWithExtensions.PortSecurityEnabled) + th.AssertFalse(t, networkWithExtensions.PortSecurityEnabled) } func TestUpdatePortSecurity(t *testing.T) { @@ -349,8 +349,8 @@ func TestUpdatePortSecurity(t *testing.T) { th.AssertNoErr(t, err) th.AssertEquals(t, "private", networkWithExtensions.Name) - th.AssertEquals(t, true, networkWithExtensions.AdminStateUp) - th.AssertEquals(t, false, networkWithExtensions.Shared) + th.AssertTrue(t, networkWithExtensions.AdminStateUp) + th.AssertFalse(t, networkWithExtensions.Shared) th.AssertEquals(t, "4e8e5957-649f-477b-9e5b-f1f75b21c03c", networkWithExtensions.ID) - th.AssertEquals(t, false, networkWithExtensions.PortSecurityEnabled) + th.AssertFalse(t, networkWithExtensions.PortSecurityEnabled) } diff --git a/openstack/networking/v2/ports/testing/requests_test.go b/openstack/networking/v2/ports/testing/requests_test.go index 112f7deab5..a6812d7f73 100644 --- a/openstack/networking/v2/ports/testing/requests_test.go +++ b/openstack/networking/v2/ports/testing/requests_test.go @@ -103,7 +103,7 @@ func TestListWithExtensions(t *testing.T) { th.AssertNoErr(t, err) th.AssertEquals(t, "ACTIVE", allPorts[0].Status) - th.AssertEquals(t, false, allPorts[0].PortSecurityEnabled) + th.AssertFalse(t, allPorts[0].PortSecurityEnabled) } func TestGet(t *testing.T) { @@ -125,7 +125,7 @@ func TestGet(t *testing.T) { th.AssertEquals(t, "ACTIVE", n.Status) th.AssertEquals(t, "", n.Name) - th.AssertEquals(t, true, n.AdminStateUp) + th.AssertTrue(t, n.AdminStateUp) th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", n.NetworkID) th.AssertEquals(t, "7e02058126cc4950b75f9970368ba177", n.TenantID) th.AssertEquals(t, "network:router_interface", n.DeviceOwner) @@ -164,7 +164,7 @@ func TestGetWithExtensions(t *testing.T) { th.AssertNoErr(t, err) th.AssertEquals(t, "ACTIVE", portWithExtensions.Status) - th.AssertEquals(t, false, portWithExtensions.PortSecurityEnabled) + th.AssertFalse(t, portWithExtensions.PortSecurityEnabled) } func TestCreate(t *testing.T) { @@ -202,7 +202,7 @@ func TestCreate(t *testing.T) { th.AssertEquals(t, "DOWN", n.Status) th.AssertEquals(t, "private-port", n.Name) - th.AssertEquals(t, true, n.AdminStateUp) + th.AssertTrue(t, n.AdminStateUp) th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", n.NetworkID) th.AssertEquals(t, "d6700c0c9ffa4f1cb322cd4a1f3906fa", n.TenantID) th.AssertEquals(t, "", n.DeviceOwner) @@ -251,7 +251,7 @@ func TestCreateOmitSecurityGroups(t *testing.T) { th.AssertEquals(t, "DOWN", n.Status) th.AssertEquals(t, "private-port", n.Name) - th.AssertEquals(t, true, n.AdminStateUp) + th.AssertTrue(t, n.AdminStateUp) th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", n.NetworkID) th.AssertEquals(t, "d6700c0c9ffa4f1cb322cd4a1f3906fa", n.TenantID) th.AssertEquals(t, "", n.DeviceOwner) @@ -301,7 +301,7 @@ func TestCreateWithNoSecurityGroup(t *testing.T) { th.AssertEquals(t, "DOWN", n.Status) th.AssertEquals(t, "private-port", n.Name) - th.AssertEquals(t, true, n.AdminStateUp) + th.AssertTrue(t, n.AdminStateUp) th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", n.NetworkID) th.AssertEquals(t, "d6700c0c9ffa4f1cb322cd4a1f3906fa", n.TenantID) th.AssertEquals(t, "", n.DeviceOwner) @@ -348,7 +348,7 @@ func TestCreateWithPropagateUplinkStatus(t *testing.T) { th.AssertEquals(t, "DOWN", n.Status) th.AssertEquals(t, "private-port", n.Name) - th.AssertEquals(t, true, n.AdminStateUp) + th.AssertTrue(t, n.AdminStateUp) th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", n.NetworkID) th.AssertEquals(t, "d6700c0c9ffa4f1cb322cd4a1f3906fa", n.TenantID) th.AssertEquals(t, "", n.DeviceOwner) @@ -398,7 +398,7 @@ func TestCreateWithValueSpecs(t *testing.T) { th.AssertEquals(t, "DOWN", n.Status) th.AssertEquals(t, "private-port", n.Name) - th.AssertEquals(t, true, n.AdminStateUp) + th.AssertTrue(t, n.AdminStateUp) th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", n.NetworkID) th.AssertEquals(t, "d6700c0c9ffa4f1cb322cd4a1f3906fa", n.TenantID) th.AssertEquals(t, "", n.DeviceOwner) @@ -517,7 +517,7 @@ func TestCreatePortSecurity(t *testing.T) { th.AssertNoErr(t, err) th.AssertEquals(t, "DOWN", portWithExt.Status) - th.AssertEquals(t, false, portWithExt.PortSecurityEnabled) + th.AssertFalse(t, portWithExt.PortSecurityEnabled) } func TestUpdate(t *testing.T) { @@ -694,7 +694,7 @@ func TestUpdatePortSecurity(t *testing.T) { th.AssertEquals(t, "DOWN", portWithExt.Status) th.AssertEquals(t, "private-port", portWithExt.Name) - th.AssertEquals(t, false, portWithExt.PortSecurityEnabled) + th.AssertFalse(t, portWithExt.PortSecurityEnabled) } func TestUpdateRevision(t *testing.T) { @@ -908,7 +908,7 @@ func TestGetWithExtraDHCPOpts(t *testing.T) { th.AssertEquals(t, "ACTIVE", s.Status) th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", s.NetworkID) th.AssertEquals(t, "d6700c0c9ffa4f1cb322cd4a1f3906fa", s.TenantID) - th.AssertEquals(t, true, s.AdminStateUp) + th.AssertTrue(t, s.AdminStateUp) th.AssertEquals(t, "port-with-extra-dhcp-opts", s.Name) th.AssertEquals(t, "", s.DeviceOwner) th.AssertEquals(t, "fa:16:3e:c9:cb:f0", s.MACAddress) @@ -974,7 +974,7 @@ func TestCreateWithExtraDHCPOpts(t *testing.T) { th.AssertEquals(t, "DOWN", s.Status) th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", s.NetworkID) th.AssertEquals(t, "d6700c0c9ffa4f1cb322cd4a1f3906fa", s.TenantID) - th.AssertEquals(t, true, s.AdminStateUp) + th.AssertTrue(t, s.AdminStateUp) th.AssertEquals(t, "port-with-extra-dhcp-opts", s.Name) th.AssertEquals(t, "", s.DeviceOwner) th.AssertEquals(t, "fa:16:3e:c9:cb:f0", s.MACAddress) @@ -1039,7 +1039,7 @@ func TestUpdateWithExtraDHCPOpts(t *testing.T) { th.AssertEquals(t, "DOWN", s.Status) th.AssertEquals(t, "a87cc70a-3e15-4acf-8205-9b711a3531b7", s.NetworkID) th.AssertEquals(t, "d6700c0c9ffa4f1cb322cd4a1f3906fa", s.TenantID) - th.AssertEquals(t, true, s.AdminStateUp) + th.AssertTrue(t, s.AdminStateUp) th.AssertEquals(t, "updated-port-with-dhcp-opts", s.Name) th.AssertEquals(t, "", s.DeviceOwner) th.AssertEquals(t, "fa:16:3e:c9:cb:f0", s.MACAddress) diff --git a/openstack/networking/v2/subnets/testing/requests_test.go b/openstack/networking/v2/subnets/testing/requests_test.go index 5e22f55848..66d3ce7570 100644 --- a/openstack/networking/v2/subnets/testing/requests_test.go +++ b/openstack/networking/v2/subnets/testing/requests_test.go @@ -72,7 +72,7 @@ func TestGet(t *testing.T) { th.AssertNoErr(t, err) th.AssertEquals(t, "my_subnet", s.Name) - th.AssertEquals(t, true, s.EnableDHCP) + th.AssertTrue(t, s.EnableDHCP) th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", s.NetworkID) th.AssertEquals(t, "4fd44f30292945e481c7b8a0c8908869", s.TenantID) th.AssertDeepEquals(t, []string{}, s.DNSNameservers) @@ -132,8 +132,8 @@ func TestCreate(t *testing.T) { th.AssertNoErr(t, err) th.AssertEquals(t, "", s.Name) - th.AssertEquals(t, true, s.DNSPublishFixedIP) - th.AssertEquals(t, true, s.EnableDHCP) + th.AssertTrue(t, s.DNSPublishFixedIP) + th.AssertTrue(t, s.EnableDHCP) th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", s.NetworkID) th.AssertEquals(t, "4fd44f30292945e481c7b8a0c8908869", s.TenantID) th.AssertDeepEquals(t, []string{"foo"}, s.DNSNameservers) @@ -187,7 +187,7 @@ func TestCreateNoGateway(t *testing.T) { th.AssertNoErr(t, err) th.AssertEquals(t, "", s.Name) - th.AssertEquals(t, true, s.EnableDHCP) + th.AssertTrue(t, s.EnableDHCP) th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a23", s.NetworkID) th.AssertEquals(t, "4fd44f30292945e481c7b8a0c8908869", s.TenantID) th.AssertDeepEquals(t, []subnets.AllocationPool{ @@ -236,7 +236,7 @@ func TestCreateDefaultGateway(t *testing.T) { th.AssertNoErr(t, err) th.AssertEquals(t, "", s.Name) - th.AssertEquals(t, true, s.EnableDHCP) + th.AssertTrue(t, s.EnableDHCP) th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a23", s.NetworkID) th.AssertEquals(t, "4fd44f30292945e481c7b8a0c8908869", s.TenantID) th.AssertDeepEquals(t, []subnets.AllocationPool{ @@ -282,7 +282,7 @@ func TestCreateIPv6RaAddressMode(t *testing.T) { th.AssertNoErr(t, err) th.AssertEquals(t, "", s.Name) - th.AssertEquals(t, true, s.EnableDHCP) + th.AssertTrue(t, s.EnableDHCP) th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", s.NetworkID) th.AssertEquals(t, "4fd44f30292945e481c7b8a0c8908869", s.TenantID) th.AssertEquals(t, 6, s.IPVersion) @@ -323,8 +323,8 @@ func TestCreateWithNoCIDR(t *testing.T) { th.AssertNoErr(t, err) th.AssertEquals(t, "", s.Name) - th.AssertEquals(t, true, s.DNSPublishFixedIP) - th.AssertEquals(t, true, s.EnableDHCP) + th.AssertTrue(t, s.DNSPublishFixedIP) + th.AssertTrue(t, s.EnableDHCP) th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", s.NetworkID) th.AssertEquals(t, "4fd44f30292945e481c7b8a0c8908869", s.TenantID) th.AssertDeepEquals(t, []string{"foo"}, s.DNSNameservers) @@ -373,8 +373,8 @@ func TestCreateWithPrefixlen(t *testing.T) { th.AssertNoErr(t, err) th.AssertEquals(t, "", s.Name) - th.AssertEquals(t, true, s.DNSPublishFixedIP) - th.AssertEquals(t, true, s.EnableDHCP) + th.AssertTrue(t, s.DNSPublishFixedIP) + th.AssertTrue(t, s.EnableDHCP) th.AssertEquals(t, "d32019d3-bc6e-4319-9c1d-6722fc136a22", s.NetworkID) th.AssertEquals(t, "4fd44f30292945e481c7b8a0c8908869", s.TenantID) th.AssertDeepEquals(t, []string{"foo"}, s.DNSNameservers) diff --git a/openstack/objectstorage/v1/objects/testing/requests_test.go b/openstack/objectstorage/v1/objects/testing/requests_test.go index 9e8766415c..a410c0206f 100644 --- a/openstack/objectstorage/v1/objects/testing/requests_test.go +++ b/openstack/objectstorage/v1/objects/testing/requests_test.go @@ -431,7 +431,7 @@ func TestGetObject(t *testing.T) { } actualHeaders, err := objects.Get(context.TODO(), client.ServiceClient(fakeServer), "testContainer", "testObject", getOpts).Extract() th.AssertNoErr(t, err) - th.AssertEquals(t, true, actualHeaders.StaticLargeObject) + th.AssertTrue(t, actualHeaders.StaticLargeObject) } func TestETag(t *testing.T) { @@ -444,7 +444,7 @@ func TestETag(t *testing.T) { _, headers, _, err := createOpts.ToObjectCreateParams() th.AssertNoErr(t, err) _, ok := headers["ETag"] - th.AssertEquals(t, false, ok) + th.AssertFalse(t, ok) hash := md5.New() _, err = io.WriteString(hash, content) @@ -471,7 +471,7 @@ func TestObjectCreateParamsWithoutSeek(t *testing.T) { th.AssertNoErr(t, err) _, ok := reader.(io.ReadSeeker) - th.AssertEquals(t, true, ok) + th.AssertTrue(t, ok) c, err := io.ReadAll(reader) th.AssertNoErr(t, err) @@ -479,7 +479,7 @@ func TestObjectCreateParamsWithoutSeek(t *testing.T) { th.AssertEquals(t, content, string(c)) _, ok = headers["ETag"] - th.AssertEquals(t, true, ok) + th.AssertTrue(t, ok) } func TestObjectCreateParamsWithSeek(t *testing.T) { @@ -490,7 +490,7 @@ func TestObjectCreateParamsWithSeek(t *testing.T) { th.AssertNoErr(t, err) _, ok := reader.(io.ReadSeeker) - th.AssertEquals(t, true, ok) + th.AssertTrue(t, ok) c, err := io.ReadAll(reader) th.AssertNoErr(t, err) @@ -498,7 +498,7 @@ func TestObjectCreateParamsWithSeek(t *testing.T) { th.AssertEquals(t, content, string(c)) _, ok = headers["ETag"] - th.AssertEquals(t, true, ok) + th.AssertTrue(t, ok) } func TestCreateTempURL(t *testing.T) { diff --git a/openstack/placement/v1/allocationcandidates/testing/requests_test.go b/openstack/placement/v1/allocationcandidates/testing/requests_test.go index 98bb29b9c9..cbab71e0dd 100644 --- a/openstack/placement/v1/allocationcandidates/testing/requests_test.go +++ b/openstack/placement/v1/allocationcandidates/testing/requests_test.go @@ -103,7 +103,7 @@ func TestListAllocationCandidatesEmptySuccess(t *testing.T) { isEmpty, err := page.IsEmpty() th.AssertNoErr(t, err) - th.AssertEquals(t, true, isEmpty) + th.AssertTrue(t, isEmpty) } func TestIsEmpty110Success(t *testing.T) { @@ -119,7 +119,7 @@ func TestIsEmpty110Success(t *testing.T) { isEmpty, err := page.IsEmpty() th.AssertNoErr(t, err) - th.AssertEquals(t, false, isEmpty) + th.AssertFalse(t, isEmpty) } func TestListAllocationCandidatesBadRequest(t *testing.T) { @@ -132,7 +132,7 @@ func TestListAllocationCandidatesBadRequest(t *testing.T) { Resources: "INVALID", }).AllPages(context.TODO()) th.AssertErr(t, err) - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) } func TestListAllocationCandidatesWithFullQuerySuccess(t *testing.T) { diff --git a/openstack/placement/v1/allocations/testing/requests_test.go b/openstack/placement/v1/allocations/testing/requests_test.go index ac259167f9..ce809342f0 100644 --- a/openstack/placement/v1/allocations/testing/requests_test.go +++ b/openstack/placement/v1/allocations/testing/requests_test.go @@ -97,7 +97,7 @@ func TestUpdateConflict(t *testing.T) { UserID: UserID, ConsumerGeneration: &staleGeneration, }).ExtractErr() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusConflict)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusConflict)) } func TestDeleteSuccess(t *testing.T) { @@ -122,7 +122,7 @@ func TestDeleteNotFound(t *testing.T) { HandleDeleteAllocationsNotFound(t, fakeServer) err := allocations.Delete(context.TODO(), client.ServiceClient(fakeServer), NotFoundConsumerUUID).ExtractErr() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } func TestManageSuccess(t *testing.T) { @@ -181,5 +181,5 @@ func TestManageConflict(t *testing.T) { ConsumerGeneration: &staleGeneration, }, }).ExtractErr() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusConflict)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusConflict)) } diff --git a/openstack/placement/v1/resourceclasses/testing/requests_test.go b/openstack/placement/v1/resourceclasses/testing/requests_test.go index 9ff18e6a71..1808665d8b 100644 --- a/openstack/placement/v1/resourceclasses/testing/requests_test.go +++ b/openstack/placement/v1/resourceclasses/testing/requests_test.go @@ -43,7 +43,7 @@ func TestGetResourceClassNotFound(t *testing.T) { HandleGetResourceClassNotFound(t, fakeServer) _, err := resourceclasses.Get(context.TODO(), client.ServiceClient(fakeServer), AbsentResourceClass).Extract() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } func TestCreateResourceClassSuccess(t *testing.T) { @@ -71,7 +71,7 @@ func TestCreateResourceClassConflict(t *testing.T) { } err := resourceclasses.Create(context.TODO(), client.ServiceClient(fakeServer), createOpts).ExtractErr() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusConflict)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusConflict)) } func TestUpdateResourceClassCreateSuccess(t *testing.T) { @@ -101,7 +101,7 @@ func TestUpdateResourceClassNonCustom(t *testing.T) { HandleUpdateResourceClassNonCustom(t, fakeServer) err := resourceclasses.Update(context.TODO(), client.ServiceClient(fakeServer), "VCPU").ExtractErr() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) } func TestDeleteResourceClassSuccess(t *testing.T) { @@ -121,7 +121,7 @@ func TestDeleteResourceClassNotFound(t *testing.T) { HandleDeleteResourceClassNotFound(t, fakeServer) err := resourceclasses.Delete(context.TODO(), client.ServiceClient(fakeServer), AbsentResourceClass).ExtractErr() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } func TestDeleteResourceClassStandardClass(t *testing.T) { @@ -132,5 +132,5 @@ func TestDeleteResourceClassStandardClass(t *testing.T) { HandleDeleteResourceClassStandardClass(t, fakeServer) err := resourceclasses.Delete(context.TODO(), client.ServiceClient(fakeServer), "VCPU").ExtractErr() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) } diff --git a/openstack/placement/v1/resourceproviders/testing/requests_test.go b/openstack/placement/v1/resourceproviders/testing/requests_test.go index 033b1c6363..9e24e3a961 100644 --- a/openstack/placement/v1/resourceproviders/testing/requests_test.go +++ b/openstack/placement/v1/resourceproviders/testing/requests_test.go @@ -204,7 +204,7 @@ func TestGetResourceProviderInventoryNotFound(t *testing.T) { HandleResourceProviderGetInventoryNotFound(t, fakeServer) _, err := resourceproviders.GetInventory(context.TODO(), client.ServiceClient(fakeServer), ResourceProviderTestID, MissingInventoryResourceClass).Extract() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } func TestUpdateResourceProvidersInventories(t *testing.T) { @@ -227,7 +227,7 @@ func TestUpdateResourceProvidersInventoriesNotFound(t *testing.T) { opts := ToUpdateInventoriesOpts(ExpectedInventories) _, err := resourceproviders.UpdateInventories(context.TODO(), client.ServiceClient(fakeServer), NonExistentRPID, opts).Extract() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } func TestUpdateResourceProviderInventory(t *testing.T) { @@ -250,7 +250,7 @@ func TestUpdateResourceProviderInventoryNotFound(t *testing.T) { opts := ToUpdateInventoryOpts(ExpectedInventory) _, err := resourceproviders.UpdateInventory(context.TODO(), client.ServiceClient(fakeServer), NonExistentRPID, PresentInventoryResourceClass, opts).Extract() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } func TestDeleteResourceProviderInventorySuccess(t *testing.T) { @@ -270,7 +270,7 @@ func TestDeleteResourceProviderInventoryInUse(t *testing.T) { HandleResourceProviderDeleteInventoryInUse(t, fakeServer) err := resourceproviders.DeleteInventory(context.TODO(), client.ServiceClient(fakeServer), ResourceProviderTestID, PresentInventoryResourceClass).ExtractErr() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusConflict)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusConflict)) } func TestDeleteResourceProviderInventoriesSuccess(t *testing.T) { @@ -290,7 +290,7 @@ func TestDeleteResourceProviderInventoriesConflict(t *testing.T) { HandleResourceProviderDeleteInventoriesConflict(t, fakeServer) err := resourceproviders.DeleteInventories(context.TODO(), client.ServiceClient(fakeServer), ResourceProviderTestID).ExtractErr() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusConflict)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusConflict)) } func TestGetResourceProvidersAllocations(t *testing.T) { @@ -366,7 +366,7 @@ func TestGetResourceProviderAggregatesNotFound(t *testing.T) { HandleResourceProviderGetAggregatesNotFound(t, fakeServer) _, err := resourceproviders.GetAggregates(context.TODO(), client.ServiceClient(fakeServer), AbsentResourceProviderID).Extract() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } func TestUpdateResourceProviderAggregatesSuccess(t *testing.T) { @@ -441,5 +441,5 @@ func TestUpdateResourceProviderAggregatesConflict(t *testing.T) { updateOpts := resourceproviders.UpdateAggregatesOpts(ExpectedUpdatedAggregates) _, err := resourceproviders.UpdateAggregates(context.TODO(), client.ServiceClient(fakeServer), ResourceProviderTestID, updateOpts).Extract() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusConflict)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusConflict)) } diff --git a/openstack/placement/v1/traits/testing/requests_test.go b/openstack/placement/v1/traits/testing/requests_test.go index ecd08005d4..93e76dbc43 100644 --- a/openstack/placement/v1/traits/testing/requests_test.go +++ b/openstack/placement/v1/traits/testing/requests_test.go @@ -97,7 +97,7 @@ func TestGetTraitNotFound(t *testing.T) { HandleGetTraitNotFound(t, fakeServer) err := traits.Get(context.TODO(), client.ServiceClient(fakeServer), AbsentTrait).ExtractErr() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } func TestCreateTraitSuccess(t *testing.T) { @@ -127,7 +127,7 @@ func TestCreateTraitInvalidName(t *testing.T) { HandleCreateTraitInvalidName(t, fakeServer) err := traits.Create(context.TODO(), client.ServiceClient(fakeServer), AbsentTrait).ExtractErr() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) } func TestDeleteTraitSuccess(t *testing.T) { @@ -147,7 +147,7 @@ func TestDeleteTraitNotFound(t *testing.T) { HandleDeleteTraitNotFound(t, fakeServer) err := traits.Delete(context.TODO(), client.ServiceClient(fakeServer), AbsentTrait).ExtractErr() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) } func TestDeleteStandardTraitFailure(t *testing.T) { @@ -157,7 +157,7 @@ func TestDeleteStandardTraitFailure(t *testing.T) { HandleDeleteStandardTraitFailure(t, fakeServer) err := traits.Delete(context.TODO(), client.ServiceClient(fakeServer), StandardHardwareTrait).ExtractErr() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusBadRequest)) } func TestDeleteTraitInUseFailure(t *testing.T) { @@ -167,5 +167,5 @@ func TestDeleteTraitInUseFailure(t *testing.T) { HandleDeleteTraitInUseFailure(t, fakeServer) err := traits.Delete(context.TODO(), client.ServiceClient(fakeServer), PresentTrait).ExtractErr() - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusConflict)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusConflict)) } diff --git a/openstack/sharedfilesystems/v2/shares/testing/request_test.go b/openstack/sharedfilesystems/v2/shares/testing/request_test.go index 64212ebbb3..3470f8bbaa 100644 --- a/openstack/sharedfilesystems/v2/shares/testing/request_test.go +++ b/openstack/sharedfilesystems/v2/shares/testing/request_test.go @@ -54,7 +54,7 @@ func TestUpdate(t *testing.T) { th.AssertNoErr(t, err) th.AssertEquals(t, "my_new_test_share", n.Name) th.AssertEquals(t, "", n.Description) - th.AssertEquals(t, false, n.IsPublic) + th.AssertFalse(t, n.IsPublic) } func TestDelete(t *testing.T) { diff --git a/openstack/sharedfilesystems/v2/sharetypes/testing/requests_test.go b/openstack/sharedfilesystems/v2/sharetypes/testing/requests_test.go index f7128635f6..a35e92972b 100644 --- a/openstack/sharedfilesystems/v2/sharetypes/testing/requests_test.go +++ b/openstack/sharedfilesystems/v2/sharetypes/testing/requests_test.go @@ -33,7 +33,7 @@ func TestCreate(t *testing.T) { th.AssertNoErr(t, err) th.AssertEquals(t, "my_new_share_type", st.Name) - th.AssertEquals(t, true, st.IsPublic) + th.AssertTrue(t, st.IsPublic) } // Verifies that a share type can't be created if the required parameters are missing diff --git a/testhelper/convenience.go b/testhelper/convenience.go index 9c61d48cf5..7e694e8485 100644 --- a/testhelper/convenience.go +++ b/testhelper/convenience.go @@ -232,6 +232,63 @@ func CheckEquals(t *testing.T, expected, actual any) { } } +// AssertEqualsIgnoreCase compares two strings case-insensitively. If they +// are not equal ignoring case, a fatal error is raised. +func AssertEqualsIgnoreCase(t *testing.T, expected, actual string) { + t.Helper() + + if !strings.EqualFold(expected, actual) { + logFatal(t, fmt.Sprintf("expected %s but got %s", green(expected), yellow(actual))) + } +} + +// CheckEqualsIgnoreCase is similar to AssertEqualsIgnoreCase, except with a non-fatal error +func CheckEqualsIgnoreCase(t *testing.T, expected, actual string) { + t.Helper() + + if !strings.EqualFold(expected, actual) { + logError(t, fmt.Sprintf("expected %s but got %s", green(expected), yellow(actual))) + } +} + +// AssertTrue checks whether the provided boolean value is true. If it is not, +// a fatal error is raised. +func AssertTrue(t *testing.T, v bool) { + t.Helper() + + if !v { + logFatal(t, "expected true, got false") + } +} + +// AssertFalse checks whether the provided boolean value is false. If it is not, +// a fatal error is raised. +func AssertFalse(t *testing.T, v bool) { + t.Helper() + + if v { + logFatal(t, "expected false, got true") + } +} + +// CheckTrue is similar to AssertTrue, except with a non-fatal error +func CheckTrue(t *testing.T, v bool) { + t.Helper() + + if !v { + logError(t, "expected true, got false") + } +} + +// CheckFalse is similar to AssertFalse, except with a non-fatal error +func CheckFalse(t *testing.T, v bool) { + t.Helper() + + if v { + logError(t, "expected false, got true") + } +} + // AssertDeepEquals - like Equals - performs a comparison - but on more complex // structures that requires deeper inspection func AssertTypeEquals(t *testing.T, expected, actual any) { diff --git a/testing/errors_test.go b/testing/errors_test.go index 0b0b9f28e1..a27d5f0bbc 100644 --- a/testing/errors_test.go +++ b/testing/errors_test.go @@ -20,11 +20,11 @@ func TestErrUnexpectedResponseCode(t *testing.T) { } th.AssertEquals(t, 404, err.GetStatusCode()) - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) - th.AssertEquals(t, false, gophercloud.ResponseCodeIs(err, http.StatusInternalServerError)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(err, http.StatusNotFound)) + th.AssertFalse(t, gophercloud.ResponseCodeIs(err, http.StatusInternalServerError)) //even if application code wraps our error, ResponseCodeIs() should still work errWrapped := fmt.Errorf("could not frobnicate the foobar: %w", err) - th.AssertEquals(t, true, gophercloud.ResponseCodeIs(errWrapped, http.StatusNotFound)) - th.AssertEquals(t, false, gophercloud.ResponseCodeIs(errWrapped, http.StatusInternalServerError)) + th.AssertTrue(t, gophercloud.ResponseCodeIs(errWrapped, http.StatusNotFound)) + th.AssertFalse(t, gophercloud.ResponseCodeIs(errWrapped, http.StatusInternalServerError)) } diff --git a/testing/provider_client_test.go b/testing/provider_client_test.go index 27dda57152..f72d47c4c8 100644 --- a/testing/provider_client_test.go +++ b/testing/provider_client_test.go @@ -211,9 +211,9 @@ func TestReauthEndLoop(t *testing.T) { wg.Wait() th.AssertEquals(t, 6, info.reauthAttempts) - th.AssertEquals(t, true, info.maxReauthReached) - th.AssertEquals(t, true, errAfter > 1) - th.AssertEquals(t, true, errUnable < 20) + th.AssertTrue(t, info.maxReauthReached) + th.AssertTrue(t, errAfter > 1) + th.AssertTrue(t, errUnable < 20) } func TestRequestThatCameDuringReauthWaitsUntilItIsCompleted(t *testing.T) { From 60117d212a0cf16bd3338fe7623b558abbf54ee8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Thu, 28 May 2026 11:57:59 +0200 Subject: [PATCH 410/429] Add missing assertions to acceptance tests Assert all fields that are set during Create and Update operations across all acceptance tests. This ensures that returned objects contain the expected values and helps catch field-mapping bugs. --- .../openstack/baremetal/v1/baremetal.go | 44 +++++++-- .../blockstorage/noauth/blockstorage.go | 11 +++ .../openstack/blockstorage/v2/blockstorage.go | 4 + .../openstack/blockstorage/v3/blockstorage.go | 8 +- .../openstack/compute/v2/compute.go | 47 ++++++++-- .../openstack/compute/v2/servergroup_test.go | 9 ++ .../openstack/compute/v2/servers_test.go | 1 + .../containerinfra/v1/containerinfra.go | 7 ++ internal/acceptance/openstack/db/v1/db.go | 10 ++- internal/acceptance/openstack/dns/v2/dns.go | 15 +++- .../acceptance/openstack/dns/v2/zones_test.go | 3 +- .../openstack/identity/v2/identity.go | 2 + .../openstack/identity/v3/credentials_test.go | 5 +- .../openstack/identity/v3/domains_test.go | 2 + .../openstack/identity/v3/endpoint_test.go | 1 + .../openstack/identity/v3/identity.go | 26 ++++-- .../openstack/identity/v3/limits_test.go | 1 + .../openstack/identity/v3/regions_test.go | 2 + .../identity/v3/registeredlimits_test.go | 7 +- .../openstack/identity/v3/roles_test.go | 2 + .../openstack/identity/v3/service_test.go | 3 + .../openstack/identity/v3/trusts_test.go | 3 + .../openstack/image/v2/imageservice.go | 11 ++- .../openstack/keymanager/v1/keymanager.go | 15 ++++ .../openstack/loadbalancer/v2/loadbalancer.go | 6 +- .../loadbalancer/v2/loadbalancers_test.go | 10 ++- .../v2/extensions/bgp/peers/peers.go | 1 + .../bgp/speakers/bgpspeakers_test.go | 2 + .../networking/v2/extensions/extensions.go | 6 ++ .../v2/extensions/fwaas_v2/fwaas_v2.go | 2 + .../networking/v2/extensions/layer3/layer3.go | 30 +++++-- .../extensions/layer3/portforwardings_test.go | 15 ++-- .../extensions/rbacpolicies/rbacpolicies.go | 3 + .../rbacpolicies/rbacpolicies_test.go | 1 + .../v2/extensions/subnetpools/subnetpools.go | 2 + .../networking/v2/extensions/taas/taas.go | 3 + .../networking/v2/extensions/trunks/trunks.go | 6 ++ .../v2/extensions/vpnaas/group_test.go | 3 + .../v2/extensions/vpnaas/ikepolicy_test.go | 4 + .../v2/extensions/vpnaas/ipsecpolicy_test.go | 2 + .../networking/v2/extensions/vpnaas/vpnaas.go | 24 +++++ .../openstack/networking/v2/networking.go | 89 +++++++++++++------ .../openstack/networking/v2/networks_test.go | 1 + .../openstack/networking/v2/ports_test.go | 6 ++ .../orchestration/v1/orchestration.go | 8 +- .../sharedfilesystems/v2/securityservices.go | 5 ++ .../sharedfilesystems/v2/sharenetworks.go | 6 ++ .../openstack/sharedfilesystems/v2/shares.go | 6 ++ .../sharedfilesystems/v2/sharetypes.go | 4 + .../sharedfilesystems/v2/snapshots.go | 5 ++ .../openstack/workflow/v2/crontrigger.go | 4 +- .../openstack/workflow/v2/execution.go | 7 +- .../openstack/workflow/v2/workflow.go | 2 + 53 files changed, 422 insertions(+), 80 deletions(-) diff --git a/internal/acceptance/openstack/baremetal/v1/baremetal.go b/internal/acceptance/openstack/baremetal/v1/baremetal.go index 4c121d18cd..27dffd7ea3 100644 --- a/internal/acceptance/openstack/baremetal/v1/baremetal.go +++ b/internal/acceptance/openstack/baremetal/v1/baremetal.go @@ -11,6 +11,7 @@ import ( "github.com/gophercloud/gophercloud/v2/openstack/baremetal/v1/nodes" "github.com/gophercloud/gophercloud/v2/openstack/baremetal/v1/portgroups" "github.com/gophercloud/gophercloud/v2/openstack/baremetal/v1/ports" + th "github.com/gophercloud/gophercloud/v2/testhelper" ) // CreateNode creates a basic node with a randomly generated name. @@ -32,8 +33,16 @@ func CreateNode(t *testing.T, client *gophercloud.ServiceClient) (*nodes.Node, e "ipmi_password": "admin", }, }).Extract() + if err != nil { + return node, err + } - return node, err + th.AssertEquals(t, name, node.Name) + th.AssertEquals(t, "ipmi", node.Driver) + th.AssertEquals(t, "ipxe", node.BootInterface) + th.AssertEquals(t, "agent", node.RAIDInterface) + + return node, nil } // DeleteNode deletes a bare metal node via its UUID. @@ -63,8 +72,14 @@ func CreateAllocation(t *testing.T, client *gophercloud.ServiceClient) (*allocat Name: name, ResourceClass: "baremetal", }).Extract() + if err != nil { + return allocation, err + } + + th.AssertEquals(t, name, allocation.Name) + th.AssertEquals(t, "baremetal", allocation.ResourceClass) - return allocation, err + return allocation, nil } // DeleteAllocation deletes a bare metal allocation via its UUID. @@ -86,8 +101,14 @@ func CreatePortGroup(t *testing.T, client *gophercloud.ServiceClient, node *node Name: name, NodeUUID: node.UUID, }).Extract() + if err != nil { + return allocation, err + } - return allocation, err + th.AssertEquals(t, name, allocation.Name) + th.AssertEquals(t, node.UUID, allocation.NodeUUID) + + return allocation, nil } // DeletePortGroup deletes a bare metal portgroup via its UUID. @@ -119,8 +140,15 @@ func CreateFakeNode(t *testing.T, client *gophercloud.ServiceClient) (*nodes.Nod "ipmi_password": "admin", }, }).Extract() + if err != nil { + return node, err + } - return node, err + th.AssertEquals(t, name, node.Name) + th.AssertEquals(t, "fake-hardware", node.Driver) + th.AssertEquals(t, "fake", node.BootInterface) + + return node, nil } func ChangeProvisionStateAndWait(ctx context.Context, client *gophercloud.ServiceClient, node *nodes.Node, @@ -196,8 +224,14 @@ func CreatePort(t *testing.T, client *gophercloud.ServiceClient, node *nodes.Nod Address: mac, PXEEnabled: &iTrue, }).Extract() + if err != nil { + return port, err + } + + th.AssertEquals(t, node.UUID, port.NodeUUID) + th.AssertEquals(t, mac, port.Address) - return port, err + return port, nil } // DeletePort - deletes a port via its UUID diff --git a/internal/acceptance/openstack/blockstorage/noauth/blockstorage.go b/internal/acceptance/openstack/blockstorage/noauth/blockstorage.go index cedccbd3cb..b1976dbd04 100644 --- a/internal/acceptance/openstack/blockstorage/noauth/blockstorage.go +++ b/internal/acceptance/openstack/blockstorage/noauth/blockstorage.go @@ -13,6 +13,7 @@ import ( "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" "github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/snapshots" "github.com/gophercloud/gophercloud/v2/openstack/blockstorage/v3/volumes" + th "github.com/gophercloud/gophercloud/v2/testhelper" ) // CreateVolume will create a volume with a random name and size of 1GB. An @@ -43,6 +44,9 @@ func CreateVolume(t *testing.T, client *gophercloud.ServiceClient) (*volumes.Vol return volume, err } + th.AssertEquals(t, volumeName, volume.Name) + th.AssertEquals(t, 1, volume.Size) + return volume, nil } @@ -80,6 +84,9 @@ func CreateVolumeFromImage(t *testing.T, client *gophercloud.ServiceClient) (*vo return volume, err } + th.AssertEquals(t, volumeName, volume.Name) + th.AssertEquals(t, 1, volume.Size) + return volume, nil } @@ -124,6 +131,10 @@ func CreateSnapshot(t *testing.T, client *gophercloud.ServiceClient, volume *vol return snapshot, err } + th.AssertEquals(t, snapshotName, snapshot.Name) + th.AssertEquals(t, snapshotDescription, snapshot.Description) + th.AssertEquals(t, volume.ID, snapshot.VolumeID) + return snapshot, nil } diff --git a/internal/acceptance/openstack/blockstorage/v2/blockstorage.go b/internal/acceptance/openstack/blockstorage/v2/blockstorage.go index c0d7effe10..fcdf5e31b6 100644 --- a/internal/acceptance/openstack/blockstorage/v2/blockstorage.go +++ b/internal/acceptance/openstack/blockstorage/v2/blockstorage.go @@ -50,6 +50,10 @@ func CreateSnapshot(t *testing.T, client *gophercloud.ServiceClient, volume *vol t.Logf("Successfully created snapshot: %s", snapshot.ID) + th.AssertEquals(t, snapshotName, snapshot.Name) + th.AssertEquals(t, snapshotDescription, snapshot.Description) + th.AssertEquals(t, volume.ID, snapshot.VolumeID) + return snapshot, nil } diff --git a/internal/acceptance/openstack/blockstorage/v3/blockstorage.go b/internal/acceptance/openstack/blockstorage/v3/blockstorage.go index b3f07747be..94a3920e3e 100644 --- a/internal/acceptance/openstack/blockstorage/v3/blockstorage.go +++ b/internal/acceptance/openstack/blockstorage/v3/blockstorage.go @@ -56,8 +56,9 @@ func CreateSnapshot(t *testing.T, client *gophercloud.ServiceClient, volume *vol } tools.PrintResource(t, snapshot) - th.AssertEquals(t, snapshot.Name, snapshotName) - th.AssertEquals(t, snapshot.VolumeID, volume.ID) + th.AssertEquals(t, snapshotName, snapshot.Name) + th.AssertEquals(t, snapshotDescription, snapshot.Description) + th.AssertEquals(t, volume.ID, snapshot.VolumeID) t.Logf("Successfully created snapshot: %s", snapshot.ID) @@ -420,7 +421,8 @@ func CreateBackup(t *testing.T, client *gophercloud.ServiceClient, volumeID stri t.Logf("Successfully created backup %s", backup.ID) tools.PrintResource(t, backup) - th.AssertEquals(t, backup.Name, backupName) + th.AssertEquals(t, backupName, backup.Name) + th.AssertEquals(t, volumeID, backup.VolumeID) return backup, nil } diff --git a/internal/acceptance/openstack/compute/v2/compute.go b/internal/acceptance/openstack/compute/v2/compute.go index 0d1aca4d7c..472f314d02 100644 --- a/internal/acceptance/openstack/compute/v2/compute.go +++ b/internal/acceptance/openstack/compute/v2/compute.go @@ -57,6 +57,8 @@ func AttachInterface(t *testing.T, client *gophercloud.ServiceClient, serverID s t.Logf("Successfully created interface %s on server %s", iface.PortID, serverID) + th.AssertEquals(t, networkID, iface.NetID) + return iface, nil } @@ -155,9 +157,9 @@ func CreateFlavor(t *testing.T, client *gophercloud.ServiceClient) (*flavors.Fla isPublic := true createOpts := flavors.CreateOpts{ Name: flavorName, - RAM: 1, + RAM: 64, VCPUs: 1, - Disk: gophercloud.IntToPointer(1), + Disk: gophercloud.IntToPointer(2), IsPublic: &isPublic, Description: flavorDescription, } @@ -170,8 +172,8 @@ func CreateFlavor(t *testing.T, client *gophercloud.ServiceClient) (*flavors.Fla t.Logf("Successfully created flavor %s", flavor.ID) th.AssertEquals(t, flavorName, flavor.Name) - th.AssertEquals(t, 1, flavor.RAM) - th.AssertEquals(t, 1, flavor.Disk) + th.AssertEquals(t, 64, flavor.RAM) + th.AssertEquals(t, 2, flavor.Disk) th.AssertEquals(t, 1, flavor.VCPUs) th.AssertTrue(t, flavor.IsPublic) th.AssertEquals(t, flavorDescription, flavor.Description) @@ -279,9 +281,9 @@ func CreatePrivateFlavor(t *testing.T, client *gophercloud.ServiceClient) (*flav isPublic := false createOpts := flavors.CreateOpts{ Name: flavorName, - RAM: 1, + RAM: 64, VCPUs: 1, - Disk: gophercloud.IntToPointer(1), + Disk: gophercloud.IntToPointer(2), IsPublic: &isPublic, } @@ -293,8 +295,8 @@ func CreatePrivateFlavor(t *testing.T, client *gophercloud.ServiceClient) (*flav t.Logf("Successfully created flavor %s", flavor.ID) th.AssertEquals(t, flavorName, flavor.Name) - th.AssertEquals(t, 1, flavor.RAM) - th.AssertEquals(t, 1, flavor.Disk) + th.AssertEquals(t, 64, flavor.RAM) + th.AssertEquals(t, 2, flavor.Disk) th.AssertEquals(t, 1, flavor.VCPUs) th.AssertFalse(t, flavor.IsPublic) @@ -319,6 +321,7 @@ func CreateSecurityGroup(t *testing.T, client *gophercloud.ServiceClient) (*secg t.Logf("Created security group: %s", securityGroup.ID) th.AssertEquals(t, name, securityGroup.Name) + th.AssertEquals(t, "something", securityGroup.Description) return securityGroup, nil } @@ -347,6 +350,8 @@ func CreateSecurityGroupRule(t *testing.T, client *gophercloud.ServiceClient, se th.AssertEquals(t, fromPort, rule.FromPort) th.AssertEquals(t, toPort, rule.ToPort) th.AssertEquals(t, securityGroupID, rule.ParentGroupID) + th.AssertEqualsIgnoreCase(t, "TCP", rule.IPProtocol) + th.AssertEquals(t, "0.0.0.0/0", rule.IPRange.CIDR) return rule, nil } @@ -406,6 +411,7 @@ func CreateServer(t *testing.T, client *gophercloud.ServiceClient) (*servers.Ser th.AssertEquals(t, name, newServer.Name) th.AssertEquals(t, choices.FlavorID, newServer.Flavor["id"]) th.AssertEquals(t, choices.ImageID, newServer.Image["id"]) + th.AssertDeepEquals(t, map[string]string{"abc": "def"}, newServer.Metadata) return newServer, nil } @@ -459,6 +465,7 @@ func CreateMicroversionServer(t *testing.T, client *gophercloud.ServiceClient) ( th.AssertEquals(t, name, newServer.Name) th.AssertEquals(t, choices.ImageID, newServer.Image["id"]) + th.AssertDeepEquals(t, map[string]string{"abc": "def"}, newServer.Metadata) return newServer, nil } @@ -585,6 +592,7 @@ func CreateServerGroup(t *testing.T, client *gophercloud.ServiceClient, policy s t.Logf("Successfully created server group %s", name) th.AssertEquals(t, name, sg.Name) + th.AssertDeepEquals(t, []string{policy}, sg.Policies) return sg, nil } @@ -613,6 +621,14 @@ func CreateServerGroupMicroversion(t *testing.T, client *gophercloud.ServiceClie t.Logf("Successfully created server group %s", name) th.AssertEquals(t, name, sg.Name) + if sg.Policy == nil { + t.Fatal("Expected Policy to be non-nil") + } + th.AssertEquals(t, policy, *sg.Policy) + if sg.Rules == nil { + t.Fatal("Expected Rules to be non-nil") + } + th.AssertEquals(t, maxServerPerHost, sg.Rules.MaxServerPerHost) return sg, nil } @@ -712,6 +728,7 @@ func CreateServerWithPublicKey(t *testing.T, client *gophercloud.ServiceClient, th.AssertEquals(t, name, newServer.Name) th.AssertEquals(t, choices.FlavorID, newServer.Flavor["id"]) th.AssertEquals(t, choices.ImageID, newServer.Image["id"]) + th.AssertEquals(t, keyPairName, newServer.KeyName) return newServer, nil } @@ -741,6 +758,15 @@ func CreateVolumeAttachment(t *testing.T, client *gophercloud.ServiceClient, blo return volumeAttachment, err } + th.AssertEquals(t, volume.ID, volumeAttachment.VolumeID) + th.AssertEquals(t, server.ID, volumeAttachment.ServerID) + if volumeAttachment.Tag != nil { + th.AssertEquals(t, tag, *volumeAttachment.Tag) + } + if volumeAttachment.DeleteOnTermination != nil { + th.AssertEquals(t, dot, *volumeAttachment.DeleteOnTermination) + } + return volumeAttachment, nil } @@ -1020,6 +1046,10 @@ func CreateRemoteConsole(t *testing.T, client *gophercloud.ServiceClient, server } t.Logf("Successfully created console: %s", remoteConsole.URL) + + th.AssertEquals(t, string(remoteconsoles.ConsoleProtocolVNC), remoteConsole.Protocol) + th.AssertEquals(t, string(remoteconsoles.ConsoleTypeNoVNC), remoteConsole.Type) + return remoteConsole, nil } @@ -1071,6 +1101,7 @@ func CreateServerNoNetwork(t *testing.T, client *gophercloud.ServiceClient) (*se th.AssertEquals(t, name, newServer.Name) th.AssertEquals(t, choices.FlavorID, newServer.Flavor["id"]) th.AssertEquals(t, choices.ImageID, newServer.Image["id"]) + th.AssertDeepEquals(t, map[string]string{"abc": "def"}, newServer.Metadata) return newServer, nil } diff --git a/internal/acceptance/openstack/compute/v2/servergroup_test.go b/internal/acceptance/openstack/compute/v2/servergroup_test.go index 5b27b9e1e9..4f59ddb1ad 100644 --- a/internal/acceptance/openstack/compute/v2/servergroup_test.go +++ b/internal/acceptance/openstack/compute/v2/servergroup_test.go @@ -23,6 +23,7 @@ func TestServergroupsCreateDelete(t *testing.T) { serverGroup, err = servergroups.Get(context.TODO(), client, serverGroup.ID).Extract() th.AssertNoErr(t, err) + th.AssertDeepEquals(t, []string{"anti-affinity"}, serverGroup.Policies) tools.PrintResource(t, serverGroup) @@ -82,6 +83,14 @@ func TestServergroupsMicroversionCreateDelete(t *testing.T) { serverGroup, err = servergroups.Get(context.TODO(), client, serverGroup.ID).Extract() th.AssertNoErr(t, err) + if serverGroup.Policy == nil { + t.Fatal("Expected Policy to be non-nil") + } + th.AssertEquals(t, "anti-affinity", *serverGroup.Policy) + if serverGroup.Rules == nil { + t.Fatal("Expected Rules to be non-nil") + } + th.AssertEquals(t, 3, serverGroup.Rules.MaxServerPerHost) tools.PrintResource(t, serverGroup) diff --git a/internal/acceptance/openstack/compute/v2/servers_test.go b/internal/acceptance/openstack/compute/v2/servers_test.go index 7c7c7fb036..cfc36323b8 100644 --- a/internal/acceptance/openstack/compute/v2/servers_test.go +++ b/internal/acceptance/openstack/compute/v2/servers_test.go @@ -308,6 +308,7 @@ func TestServersActionRebuild(t *testing.T) { th.AssertNoErr(t, err) th.AssertEquals(t, server.ID, rebuilt.ID) + th.AssertEquals(t, rebuildOpts.Name, rebuilt.Name) if err = WaitForComputeStatus(client, rebuilt, "REBUILD"); err != nil { t.Fatal(err) diff --git a/internal/acceptance/openstack/containerinfra/v1/containerinfra.go b/internal/acceptance/openstack/containerinfra/v1/containerinfra.go index 978787ef5e..2ebe98ee6c 100644 --- a/internal/acceptance/openstack/containerinfra/v1/containerinfra.go +++ b/internal/acceptance/openstack/containerinfra/v1/containerinfra.go @@ -76,6 +76,13 @@ func CreateClusterTemplateCOE(t *testing.T, client *gophercloud.ServiceClient, c th.AssertDeepEquals(t, labels, clusterTemplate.Labels) th.AssertEquals(t, choices.ExternalNetworkID, clusterTemplate.ExternalNetworkID) th.AssertEquals(t, choices.MagnumImageID, clusterTemplate.ImageID) + th.AssertEquals(t, coe, clusterTemplate.COE) + th.AssertEquals(t, "8.8.8.8", clusterTemplate.DNSNameServer) + th.AssertEquals(t, "overlay2", clusterTemplate.DockerStorageDriver) + th.AssertFalse(t, clusterTemplate.FloatingIPEnabled) + th.AssertFalse(t, clusterTemplate.Public) + th.AssertFalse(t, clusterTemplate.RegistryEnabled) + th.AssertEquals(t, "vm", clusterTemplate.ServerType) return clusterTemplate, nil } diff --git a/internal/acceptance/openstack/db/v1/db.go b/internal/acceptance/openstack/db/v1/db.go index fe529a0133..fc1fc60786 100644 --- a/internal/acceptance/openstack/db/v1/db.go +++ b/internal/acceptance/openstack/db/v1/db.go @@ -13,6 +13,7 @@ import ( "github.com/gophercloud/gophercloud/v2/openstack/db/v1/databases" "github.com/gophercloud/gophercloud/v2/openstack/db/v1/instances" "github.com/gophercloud/gophercloud/v2/openstack/db/v1/users" + th "github.com/gophercloud/gophercloud/v2/testhelper" ) // CreateDatabase will create a database with a randomly generated name. @@ -67,7 +68,14 @@ func CreateInstance(t *testing.T, client *gophercloud.ServiceClient) (*instances return instance, err } - return instances.Get(context.TODO(), client, instance.ID).Extract() + result, err := instances.Get(context.TODO(), client, instance.ID).Extract() + if err != nil { + return result, err + } + + th.AssertEquals(t, name, result.Name) + + return result, nil } // CreateUser will create a user with a randomly generated name. diff --git a/internal/acceptance/openstack/dns/v2/dns.go b/internal/acceptance/openstack/dns/v2/dns.go index 42e431b3cb..4140f601cf 100644 --- a/internal/acceptance/openstack/dns/v2/dns.go +++ b/internal/acceptance/openstack/dns/v2/dns.go @@ -43,7 +43,10 @@ func CreateRecordSet(t *testing.T, client *gophercloud.ServiceClient, zone *zone t.Logf("Created record set: %s", newRS.Name) - th.AssertEquals(t, newRS.Name, zone.Name) + th.AssertEquals(t, zone.Name, newRS.Name) + th.AssertEquals(t, "A", newRS.Type) + th.AssertEquals(t, 3600, newRS.TTL) + th.AssertEquals(t, "Test recordset", newRS.Description) return rs, nil } @@ -78,7 +81,10 @@ func CreateZone(t *testing.T, client *gophercloud.ServiceClient) (*zones.Zone, e t.Logf("Created Zone: %s", zoneName) - th.AssertEquals(t, newZone.Name, zoneName) + th.AssertEquals(t, zoneName, newZone.Name) + th.AssertEquals(t, "root@example.com", newZone.Email) + th.AssertEquals(t, "PRIMARY", newZone.Type) + th.AssertEquals(t, "Test zone", newZone.Description) th.AssertEquals(t, 7200, newZone.TTL) return newZone, nil @@ -114,7 +120,8 @@ func CreateSecondaryZone(t *testing.T, client *gophercloud.ServiceClient) (*zone t.Logf("Created Zone: %s", zoneName) - th.AssertEquals(t, newZone.Name, zoneName) + th.AssertEquals(t, zoneName, newZone.Name) + th.AssertEquals(t, "SECONDARY", newZone.Type) th.AssertEquals(t, "10.0.0.1", newZone.Masters[0]) return newZone, nil @@ -148,6 +155,8 @@ func CreateTransferRequest(t *testing.T, client *gophercloud.ServiceClient, zone th.AssertEquals(t, newTransferRequest.ZoneID, zone.ID) th.AssertEquals(t, newTransferRequest.ZoneName, zone.Name) + th.AssertEquals(t, targetProjectID, newTransferRequest.TargetProjectID) + th.AssertEquals(t, "Test transfer request", newTransferRequest.Description) return newTransferRequest, nil } diff --git a/internal/acceptance/openstack/dns/v2/zones_test.go b/internal/acceptance/openstack/dns/v2/zones_test.go index fd26249448..f7ddd69fec 100644 --- a/internal/acceptance/openstack/dns/v2/zones_test.go +++ b/internal/acceptance/openstack/dns/v2/zones_test.go @@ -42,7 +42,7 @@ func TestZonesCRUD(t *testing.T) { description := "" updateOpts := zones.UpdateOpts{ Description: &description, - TTL: 0, + TTL: 3600, } newZone, err := zones.Update(context.TODO(), client, zone.ID, updateOpts).Extract() @@ -51,4 +51,5 @@ func TestZonesCRUD(t *testing.T) { tools.PrintResource(t, &newZone) th.AssertEquals(t, newZone.Description, description) + th.AssertEquals(t, 3600, newZone.TTL) } diff --git a/internal/acceptance/openstack/identity/v2/identity.go b/internal/acceptance/openstack/identity/v2/identity.go index 032a01a72f..3c04cffa90 100644 --- a/internal/acceptance/openstack/identity/v2/identity.go +++ b/internal/acceptance/openstack/identity/v2/identity.go @@ -81,6 +81,7 @@ func CreateUser(t *testing.T, client *gophercloud.ServiceClient, tenant *tenants } th.AssertEquals(t, userName, user.Name) + th.AssertFalse(t, user.Enabled) return user, nil } @@ -191,6 +192,7 @@ func UpdateUser(t *testing.T, client *gophercloud.ServiceClient, user *users.Use } th.AssertEquals(t, userName, newUser.Name) + th.AssertEquals(t, updateOpts.Email, newUser.Email) return newUser, nil } diff --git a/internal/acceptance/openstack/identity/v3/credentials_test.go b/internal/acceptance/openstack/identity/v3/credentials_test.go index 9590f41bff..51345fd4bc 100644 --- a/internal/acceptance/openstack/identity/v3/credentials_test.go +++ b/internal/acceptance/openstack/identity/v3/credentials_test.go @@ -89,7 +89,10 @@ func TestCredentialsCRUD(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, updateCredential) - th.AssertEquals(t, updateCredential.Blob, updateOpts.Blob) + th.AssertEquals(t, updateOpts.Blob, updateCredential.Blob) + th.AssertEquals(t, updateOpts.Type, updateCredential.Type) + th.AssertEquals(t, updateOpts.UserID, updateCredential.UserID) + th.AssertEquals(t, updateOpts.ProjectID, updateCredential.ProjectID) } func TestCredentialsValidateS3(t *testing.T) { diff --git a/internal/acceptance/openstack/identity/v3/domains_test.go b/internal/acceptance/openstack/identity/v3/domains_test.go index 48d32b6e18..0031158702 100644 --- a/internal/acceptance/openstack/identity/v3/domains_test.go +++ b/internal/acceptance/openstack/identity/v3/domains_test.go @@ -92,6 +92,7 @@ func TestDomainsCRUD(t *testing.T) { tools.PrintResource(t, domain) th.AssertEquals(t, domain.Description, description) + th.AssertTrue(t, domain.Enabled) var iFalse = false description = "" @@ -106,4 +107,5 @@ func TestDomainsCRUD(t *testing.T) { tools.PrintResource(t, newDomain) th.AssertEquals(t, newDomain.Description, description) + th.AssertFalse(t, newDomain.Enabled) } diff --git a/internal/acceptance/openstack/identity/v3/endpoint_test.go b/internal/acceptance/openstack/identity/v3/endpoint_test.go index 26e86c5352..814c364e35 100644 --- a/internal/acceptance/openstack/identity/v3/endpoint_test.go +++ b/internal/acceptance/openstack/identity/v3/endpoint_test.go @@ -140,4 +140,5 @@ func TestEndpointCRUD(t *testing.T) { th.AssertEquals(t, "https://example-updated.com", newEndpoint.URL) th.AssertEquals(t, newEndpoint.Description, description) + th.AssertEquals(t, "new-endpoint", newEndpoint.Name) } diff --git a/internal/acceptance/openstack/identity/v3/identity.go b/internal/acceptance/openstack/identity/v3/identity.go index a71c914430..f0c07a2af4 100644 --- a/internal/acceptance/openstack/identity/v3/identity.go +++ b/internal/acceptance/openstack/identity/v3/identity.go @@ -44,8 +44,11 @@ func CreateEndpoint(t *testing.T, client *gophercloud.ServiceClient, c *endpoint t.Logf("Successfully created endpoint %s with ID %s", name, endpoint.ID) - th.AssertEquals(t, endpoint.Name, name) - th.AssertEquals(t, endpoint.Description, description) + th.AssertEquals(t, name, endpoint.Name) + th.AssertEquals(t, description, endpoint.Description) + th.AssertEquals(t, string(createOpts.Availability), string(endpoint.Availability)) + th.AssertEquals(t, createOpts.ServiceID, endpoint.ServiceID) + th.AssertEquals(t, createOpts.URL, endpoint.URL) return endpoint, nil } @@ -106,7 +109,8 @@ func CreateUser(t *testing.T, client *gophercloud.ServiceClient, c *users.Create t.Logf("Successfully created user %s with ID %s", name, user.ID) - th.AssertEquals(t, user.Name, name) + th.AssertEquals(t, name, user.Name) + th.AssertEquals(t, createOpts.Description, user.Description) return user, nil } @@ -135,7 +139,8 @@ func CreateGroup(t *testing.T, client *gophercloud.ServiceClient, c *groups.Crea t.Logf("Successfully created group %s with ID %s", name, group.ID) - th.AssertEquals(t, group.Name, name) + th.AssertEquals(t, name, group.Name) + th.AssertEquals(t, createOpts.Description, group.Description) return group, nil } @@ -164,7 +169,8 @@ func CreateDomain(t *testing.T, client *gophercloud.ServiceClient, c *domains.Cr t.Logf("Successfully created domain %s with ID %s", name, domain.ID) - th.AssertEquals(t, domain.Name, name) + th.AssertEquals(t, name, domain.Name) + th.AssertEquals(t, createOpts.Description, domain.Description) return domain, nil } @@ -198,7 +204,10 @@ func CreateRole(t *testing.T, client *gophercloud.ServiceClient, c *roles.Create t.Logf("Successfully created role %s with ID %s", name, role.ID) - th.AssertEquals(t, role.Name, name) + th.AssertEquals(t, name, role.Name) + if createOpts.Description != "" { + th.AssertEquals(t, createOpts.Description, role.Description) + } return role, nil } @@ -228,6 +237,7 @@ func CreateRegion(t *testing.T, client *gophercloud.ServiceClient, c *regions.Cr t.Logf("Successfully created region %s", id) th.AssertEquals(t, region.ID, id) + th.AssertEquals(t, createOpts.Description, region.Description) return region, nil } @@ -405,6 +415,10 @@ func CreateTrust(t *testing.T, client *gophercloud.ServiceClient, createOpts tru t.Logf("Successfully created trust %s", trust.ID) + th.AssertEquals(t, createOpts.TrusteeUserID, trust.TrusteeUserID) + th.AssertEquals(t, createOpts.TrustorUserID, trust.TrustorUserID) + th.AssertEquals(t, createOpts.ProjectID, trust.ProjectID) + return trust, nil } diff --git a/internal/acceptance/openstack/identity/v3/limits_test.go b/internal/acceptance/openstack/identity/v3/limits_test.go index 72dc12e4fb..348af5b8ab 100644 --- a/internal/acceptance/openstack/identity/v3/limits_test.go +++ b/internal/acceptance/openstack/identity/v3/limits_test.go @@ -111,6 +111,7 @@ func TestLimitsCRUD(t *testing.T) { th.AssertEquals(t, globalResourceName, createdLimits[0].ResourceName) th.AssertEquals(t, serviceID, createdLimits[0].ServiceID) th.AssertEquals(t, project.ID, createdLimits[0].ProjectID) + th.AssertEquals(t, "RegionOne", createdLimits[0].RegionID) limitID := createdLimits[0].ID diff --git a/internal/acceptance/openstack/identity/v3/regions_test.go b/internal/acceptance/openstack/identity/v3/regions_test.go index 4a4df55f9e..d8d2724a06 100644 --- a/internal/acceptance/openstack/identity/v3/regions_test.go +++ b/internal/acceptance/openstack/identity/v3/regions_test.go @@ -76,6 +76,8 @@ func TestRegionsCRUD(t *testing.T) { tools.PrintResource(t, region) tools.PrintResource(t, region.Extra) + th.AssertEquals(t, "Region for testing", region.Description) + var description = "" updateOpts := regions.UpdateOpts{ Description: &description, diff --git a/internal/acceptance/openstack/identity/v3/registeredlimits_test.go b/internal/acceptance/openstack/identity/v3/registeredlimits_test.go index ee0b61022b..a0458916ff 100644 --- a/internal/acceptance/openstack/identity/v3/registeredlimits_test.go +++ b/internal/acceptance/openstack/identity/v3/registeredlimits_test.go @@ -90,9 +90,10 @@ func TestRegisteredLimitsCRUD(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, updated_registered_limit) - th.AssertEquals(t, updated_registered_limit.Description, updatedDescription) - th.AssertEquals(t, updated_registered_limit.DefaultLimit, updatedDefaultLimit) - th.AssertEquals(t, updated_registered_limit.ResourceName, updatedResourceName) + th.AssertEquals(t, updatedDescription, updated_registered_limit.Description) + th.AssertEquals(t, updatedDefaultLimit, updated_registered_limit.DefaultLimit) + th.AssertEquals(t, updatedResourceName, updated_registered_limit.ResourceName) + th.AssertEquals(t, serviceID, updated_registered_limit.ServiceID) // Delete the registered limit del_err := registeredlimits.Delete(context.TODO(), client, createdRegisteredLimits[0].ID).ExtractErr() diff --git a/internal/acceptance/openstack/identity/v3/roles_test.go b/internal/acceptance/openstack/identity/v3/roles_test.go index f754232285..fe94ada301 100644 --- a/internal/acceptance/openstack/identity/v3/roles_test.go +++ b/internal/acceptance/openstack/identity/v3/roles_test.go @@ -77,6 +77,8 @@ func TestRolesCRUD(t *testing.T) { tools.PrintResource(t, role) tools.PrintResource(t, role.Extra) + th.AssertEquals(t, "test description", role.Description) + listOpts := roles.ListOpts{ DomainID: "default", } diff --git a/internal/acceptance/openstack/identity/v3/service_test.go b/internal/acceptance/openstack/identity/v3/service_test.go index 7878c83207..496b7fb5b2 100644 --- a/internal/acceptance/openstack/identity/v3/service_test.go +++ b/internal/acceptance/openstack/identity/v3/service_test.go @@ -61,6 +61,8 @@ func TestServicesCRUD(t *testing.T) { tools.PrintResource(t, service) tools.PrintResource(t, service.Extra) + th.AssertEquals(t, "testing", service.Type) + updateOpts := services.UpdateOpts{ Type: "testing2", Extra: map[string]any{ @@ -76,4 +78,5 @@ func TestServicesCRUD(t *testing.T) { tools.PrintResource(t, newService.Extra) th.AssertEquals(t, "Test Users", newService.Extra["description"]) + th.AssertEquals(t, "testing2", newService.Type) } diff --git a/internal/acceptance/openstack/identity/v3/trusts_test.go b/internal/acceptance/openstack/identity/v3/trusts_test.go index 1f3145accb..e6a894c7c3 100644 --- a/internal/acceptance/openstack/identity/v3/trusts_test.go +++ b/internal/acceptance/openstack/identity/v3/trusts_test.go @@ -113,6 +113,9 @@ func TestTrustCRUD(t *testing.T) { th.AssertNoErr(t, err) th.AssertEquals(t, p.ExpiresAt, expiresAt) th.AssertTrue(t, p.DeletedAt.IsZero()) + th.AssertEquals(t, trusteeUser.ID, p.TrusteeUserID) + th.AssertEquals(t, adminUser.ID, p.TrustorUserID) + th.AssertEquals(t, trusteeProject.ID, p.ProjectID) tools.PrintResource(t, p) diff --git a/internal/acceptance/openstack/image/v2/imageservice.go b/internal/acceptance/openstack/image/v2/imageservice.go index 8af457fc22..d9076ee9ce 100644 --- a/internal/acceptance/openstack/image/v2/imageservice.go +++ b/internal/acceptance/openstack/image/v2/imageservice.go @@ -7,6 +7,7 @@ import ( "io" "net/http" "os" + "sort" "testing" "github.com/gophercloud/gophercloud/v2" @@ -55,7 +56,15 @@ func CreateEmptyImage(t *testing.T, client *gophercloud.ServiceClient) (*images. t.Logf("Created image %s: %#v", name, newImage) - th.CheckEquals(t, newImage.Name, name) + th.CheckEquals(t, name, newImage.Name) + th.CheckEquals(t, "bare", newImage.ContainerFormat) + th.CheckEquals(t, "qcow2", newImage.DiskFormat) + th.CheckEquals(t, images.ImageVisibilityPrivate, newImage.Visibility) + expectedTags := []string{"bar", "baz", "foo"} + actualTags := make([]string, len(newImage.Tags)) + copy(actualTags, newImage.Tags) + sort.Strings(actualTags) + th.AssertDeepEquals(t, expectedTags, actualTags) th.CheckEquals(t, "x86_64", newImage.Properties["architecture"]) th.CheckEquals(t, "{'hypervisor_type': 'qemu', 'architecture': 'x86_64'}", newImage.Properties["properties"]) return newImage, nil diff --git a/internal/acceptance/openstack/keymanager/v1/keymanager.go b/internal/acceptance/openstack/keymanager/v1/keymanager.go index 1827797b21..295b71241d 100644 --- a/internal/acceptance/openstack/keymanager/v1/keymanager.go +++ b/internal/acceptance/openstack/keymanager/v1/keymanager.go @@ -250,6 +250,7 @@ func CreateCertificateSecret(t *testing.T, client *gophercloud.ServiceClient, ce th.AssertEquals(t, secret.Name, name) th.AssertEquals(t, "rsa", secret.Algorithm) + th.AssertEquals(t, "certificate", secret.SecretType) return secret, nil } @@ -290,6 +291,9 @@ func CreateEmptySecret(t *testing.T, client *gophercloud.ServiceClient) (*secret th.AssertEquals(t, secret.Name, secretName) th.AssertEquals(t, "aes", secret.Algorithm) + th.AssertEquals(t, 256, secret.BitLength) + th.AssertEquals(t, "cbc", secret.Mode) + th.AssertEquals(t, "opaque", secret.SecretType) return secret, nil } @@ -424,6 +428,9 @@ func CreatePassphraseSecret(t *testing.T, client *gophercloud.ServiceClient, pas th.AssertEquals(t, secret.Name, secretName) th.AssertEquals(t, "aes", secret.Algorithm) + th.AssertEquals(t, 256, secret.BitLength) + th.AssertEquals(t, "cbc", secret.Mode) + th.AssertEquals(t, "passphrase", secret.SecretType) return secret, nil } @@ -466,6 +473,7 @@ func CreatePublicSecret(t *testing.T, client *gophercloud.ServiceClient, pub []b th.AssertEquals(t, secret.Name, name) th.AssertEquals(t, "rsa", secret.Algorithm) + th.AssertEquals(t, "public", secret.SecretType) return secret, nil } @@ -508,6 +516,7 @@ func CreatePrivateSecret(t *testing.T, client *gophercloud.ServiceClient, priv [ th.AssertEquals(t, secret.Name, name) th.AssertEquals(t, "rsa", secret.Algorithm) + th.AssertEquals(t, "private", secret.SecretType) return secret, nil } @@ -552,6 +561,9 @@ func CreateSecretWithPayload(t *testing.T, client *gophercloud.ServiceClient, pa th.AssertEquals(t, secret.Name, secretName) th.AssertEquals(t, "aes", secret.Algorithm) + th.AssertEquals(t, 256, secret.BitLength) + th.AssertEquals(t, "cbc", secret.Mode) + th.AssertEquals(t, "opaque", secret.SecretType) th.AssertEquals(t, secret.Expiration, expiration) return secret, nil @@ -598,6 +610,9 @@ func CreateSymmetricSecret(t *testing.T, client *gophercloud.ServiceClient) (*se th.AssertEquals(t, secret.Name, name) th.AssertEquals(t, "aes", secret.Algorithm) + th.AssertEquals(t, 256, secret.BitLength) + th.AssertEquals(t, "cbc", secret.Mode) + th.AssertEquals(t, "symmetric", secret.SecretType) return secret, nil } diff --git a/internal/acceptance/openstack/loadbalancer/v2/loadbalancer.go b/internal/acceptance/openstack/loadbalancer/v2/loadbalancer.go index 46aa05fcc4..a086a27053 100644 --- a/internal/acceptance/openstack/loadbalancer/v2/loadbalancer.go +++ b/internal/acceptance/openstack/loadbalancer/v2/loadbalancer.go @@ -322,7 +322,11 @@ func CreateMember(t *testing.T, client *gophercloud.ServiceClient, lb *loadbalan return member, fmt.Errorf("timed out waiting for loadbalancer to become active: %s", err) } - th.AssertEquals(t, member.Name, memberName) + th.AssertEquals(t, memberName, member.Name) + th.AssertEquals(t, memberPort, member.ProtocolPort) + th.AssertEquals(t, memberWeight, member.Weight) + th.AssertEquals(t, memberAddress, member.Address) + th.AssertEquals(t, subnetID, member.SubnetID) return member, nil } diff --git a/internal/acceptance/openstack/loadbalancer/v2/loadbalancers_test.go b/internal/acceptance/openstack/loadbalancer/v2/loadbalancers_test.go index 8724cbabdd..c0942d4651 100644 --- a/internal/acceptance/openstack/loadbalancer/v2/loadbalancers_test.go +++ b/internal/acceptance/openstack/loadbalancer/v2/loadbalancers_test.go @@ -358,8 +358,8 @@ func TestLoadbalancersCRUD(t *testing.T) { tools.PrintResource(t, newListener) - th.AssertEquals(t, newListener.Name, listenerName) - th.AssertEquals(t, newListener.Description, listenerDescription) + th.AssertEquals(t, listenerName, newListener.Name) + th.AssertEquals(t, listenerDescription, newListener.Description) listenerStats, err := listeners.GetStats(context.TODO(), lbClient, listener.ID).Extract() th.AssertNoErr(t, err) @@ -430,7 +430,8 @@ func TestLoadbalancersCRUD(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, newMember) - th.AssertEquals(t, newMember.Name, memberName) + th.AssertEquals(t, memberName, newMember.Name) + th.AssertEquals(t, newWeight, newMember.Weight) newWeight = tools.RandomInt(11, 100) memberOpts := pools.BatchUpdateMemberOpts{ @@ -534,6 +535,7 @@ func TestLoadbalancersCascadeCRUD(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, newListener) + th.AssertEquals(t, listenerDescription, newListener.Description) // Pool pool, err := CreatePool(t, lbClient, lb) @@ -554,6 +556,7 @@ func TestLoadbalancersCascadeCRUD(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, newPool) + th.AssertEquals(t, poolDescription, newPool.Description) // Member member, err := CreateMember(t, lbClient, lb, newPool, subnet.ID, subnet.CIDR) @@ -574,6 +577,7 @@ func TestLoadbalancersCascadeCRUD(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, newMember) + th.AssertEquals(t, newWeight, newMember.Weight) // Monitor monitor, err := CreateMonitor(t, lbClient, lb, newPool) diff --git a/internal/acceptance/openstack/networking/v2/extensions/bgp/peers/peers.go b/internal/acceptance/openstack/networking/v2/extensions/bgp/peers/peers.go index 198673498b..e5d071b2b8 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/bgp/peers/peers.go +++ b/internal/acceptance/openstack/networking/v2/extensions/bgp/peers/peers.go @@ -27,6 +27,7 @@ func CreateBGPPeer(t *testing.T, client *gophercloud.ServiceClient) (*peers.BGPP th.AssertEquals(t, bgpPeer.Name, opts.Name) th.AssertEquals(t, bgpPeer.RemoteAS, opts.RemoteAS) th.AssertEquals(t, bgpPeer.PeerIP, opts.PeerIP) + th.AssertEquals(t, opts.AuthType, bgpPeer.AuthType) t.Logf("Successfully created BGP Peer") tools.PrintResource(t, bgpPeer) return bgpPeer, err diff --git a/internal/acceptance/openstack/networking/v2/extensions/bgp/speakers/bgpspeakers_test.go b/internal/acceptance/openstack/networking/v2/extensions/bgp/speakers/bgpspeakers_test.go index 1917f5f2f1..d4e96afa19 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/bgp/speakers/bgpspeakers_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/bgp/speakers/bgpspeakers_test.go @@ -58,6 +58,8 @@ func TestBGPSpeakerCRUD(t *testing.T) { speakerUpdated, err := speakers.Update(context.TODO(), client, bgpSpeaker.ID, opts).Extract() th.AssertNoErr(t, err) th.AssertEquals(t, speakerUpdated.Name, *opts.Name) + th.AssertFalse(t, speakerUpdated.AdvertiseTenantNetworks) + th.AssertTrue(t, speakerUpdated.AdvertiseFloatingIPHostRoutes) t.Logf("Updated the BGP Speaker, name set from %s to %s", bgpSpeaker.Name, speakerUpdated.Name) // Get a BGP Speaker diff --git a/internal/acceptance/openstack/networking/v2/extensions/extensions.go b/internal/acceptance/openstack/networking/v2/extensions/extensions.go index ae0b52f595..3b21db64e4 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/extensions.go +++ b/internal/acceptance/openstack/networking/v2/extensions/extensions.go @@ -46,6 +46,7 @@ func CreateExternalNetwork(t *testing.T, client *gophercloud.ServiceClient) (*ne th.AssertEquals(t, networkName, network.Name) th.AssertEquals(t, networkDescription, network.Description) + th.AssertTrue(t, network.AdminStateUp) return network, nil } @@ -137,6 +138,11 @@ func CreateSecurityGroupRule(t *testing.T, client *gophercloud.ServiceClient, se th.AssertEquals(t, rule.SecGroupID, secGroupID) th.AssertEquals(t, rule.Description, description) + th.AssertEquals(t, "ingress", rule.Direction) + th.AssertEquals(t, "IPv4", rule.EtherType) + th.AssertEquals(t, fromPort, rule.PortRangeMin) + th.AssertEquals(t, toPort, rule.PortRangeMax) + th.AssertEquals(t, string(rules.ProtocolTCP), rule.Protocol) return rule, nil } diff --git a/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/fwaas_v2.go b/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/fwaas_v2.go index 74dda5a8e5..2e0a4dabf6 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/fwaas_v2.go +++ b/internal/acceptance/openstack/networking/v2/extensions/fwaas_v2/fwaas_v2.go @@ -167,6 +167,8 @@ func CreateGroup(t *testing.T, client *gophercloud.ServiceClient) (*groups.Group t.Logf("firewall group %s successfully created", groupName) th.AssertEquals(t, group.Name, groupName) + th.AssertEquals(t, description, group.Description) + th.AssertTrue(t, group.AdminStateUp) return group, nil } diff --git a/internal/acceptance/openstack/networking/v2/extensions/layer3/layer3.go b/internal/acceptance/openstack/networking/v2/extensions/layer3/layer3.go index 8d5053977f..be2324267c 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/layer3/layer3.go +++ b/internal/acceptance/openstack/networking/v2/extensions/layer3/layer3.go @@ -37,7 +37,8 @@ func CreateFloatingIP(t *testing.T, client *gophercloud.ServiceClient, networkID t.Logf("Created floating IP.") - th.AssertEquals(t, floatingIP.Description, fipDescription) + th.AssertEquals(t, fipDescription, floatingIP.Description) + th.AssertEquals(t, networkID, floatingIP.FloatingNetworkID) return floatingIP, err } @@ -62,8 +63,9 @@ func CreateFloatingIPWithFixedIP(t *testing.T, client *gophercloud.ServiceClient t.Logf("Created floating IP.") - th.AssertEquals(t, floatingIP.Description, fipDescription) - th.AssertEquals(t, floatingIP.FixedIP, fixedIP) + th.AssertEquals(t, fipDescription, floatingIP.Description) + th.AssertEquals(t, networkID, floatingIP.FloatingNetworkID) + th.AssertEquals(t, fixedIP, floatingIP.FixedIP) return floatingIP, err } @@ -92,7 +94,12 @@ func CreatePortForwarding(t *testing.T, client *gophercloud.ServiceClient, fipID t.Logf("Created Port Forwarding.") + th.AssertEquals(t, pfDescription, pf.Description) th.AssertEquals(t, "tcp", pf.Protocol) + th.AssertEquals(t, 25, pf.InternalPort) + th.AssertEquals(t, 2230, pf.ExternalPort) + th.AssertEquals(t, internalIP, pf.InternalIPAddress) + th.AssertEquals(t, portID, pf.InternalPortID) return pf, err } @@ -109,7 +116,7 @@ func CreatePortRangeForwarding(t *testing.T, client *gophercloud.ServiceClient, Description: pfDescription, Protocol: "tcp", InternalPortRange: "1200:1299", - ExternalPortRange: "1200:1299", + ExternalPortRange: "1300:1399", InternalIPAddress: internalIP, InternalPortID: portID, } @@ -121,7 +128,12 @@ func CreatePortRangeForwarding(t *testing.T, client *gophercloud.ServiceClient, t.Logf("Created Port Range Forwarding.") + th.AssertEquals(t, pfDescription, pf.Description) th.AssertEquals(t, "tcp", pf.Protocol) + th.AssertEquals(t, "1200:1299", pf.InternalPortRange) + th.AssertEquals(t, "1300:1399", pf.ExternalPortRange) + th.AssertEquals(t, internalIP, pf.InternalIPAddress) + th.AssertEquals(t, portID, pf.InternalPortID) return pf, err } @@ -177,8 +189,9 @@ func CreateExternalRouter(t *testing.T, client *gophercloud.ServiceClient) (*rou t.Logf("Created router: %s", routerName) - th.AssertEquals(t, router.Name, routerName) - th.AssertEquals(t, router.Description, routerDescription) + th.AssertEquals(t, routerName, router.Name) + th.AssertEquals(t, routerDescription, router.Description) + th.AssertTrue(t, router.AdminStateUp) return router, nil } @@ -209,8 +222,9 @@ func CreateRouter(t *testing.T, client *gophercloud.ServiceClient, networkID str t.Logf("Created router: %s", routerName) - th.AssertEquals(t, router.Name, routerName) - th.AssertEquals(t, router.Description, routerDescription) + th.AssertEquals(t, routerName, router.Name) + th.AssertEquals(t, routerDescription, router.Description) + th.AssertTrue(t, router.AdminStateUp) return router, nil } diff --git a/internal/acceptance/openstack/networking/v2/extensions/layer3/portforwardings_test.go b/internal/acceptance/openstack/networking/v2/extensions/layer3/portforwardings_test.go index 29f3ba62d0..ba5983cb77 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/layer3/portforwardings_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/layer3/portforwardings_test.go @@ -83,6 +83,9 @@ func TestLayer3PortForwardingsCreateDelete(t *testing.T) { newPf, err = portforwarding.Get(context.TODO(), client, fip.ID, pf.ID).Extract() th.AssertNoErr(t, err) th.AssertEquals(t, "", newPf.Description) + th.AssertEquals(t, "udp", newPf.Protocol) + th.AssertEquals(t, 30, newPf.InternalPort) + th.AssertEquals(t, 678, newPf.ExternalPort) // Test updating port range newRangePf, err := portforwarding.Get(context.TODO(), client, fip.ID, pfRange.ID).Extract() @@ -90,9 +93,9 @@ func TestLayer3PortForwardingsCreateDelete(t *testing.T) { updateOpts = portforwarding.UpdateOpts{ Description: new(string), - Protocol: "tcp", - InternalPortRange: "1300:1399", - ExternalPortRange: "1300:1399", + Protocol: "udp", + InternalPortRange: "1400:1499", + ExternalPortRange: "1500:1599", } _, err = portforwarding.Update(context.TODO(), client, fip.ID, newRangePf.ID, updateOpts).Extract() @@ -101,9 +104,9 @@ func TestLayer3PortForwardingsCreateDelete(t *testing.T) { newRangePf, err = portforwarding.Get(context.TODO(), client, fip.ID, pfRange.ID).Extract() th.AssertNoErr(t, err) th.AssertEquals(t, "", newRangePf.Description) - th.AssertEquals(t, "tcp", newRangePf.Protocol) - th.AssertEquals(t, "1300:1399", newRangePf.InternalPortRange) - th.AssertEquals(t, "1300:1399", newRangePf.ExternalPortRange) + th.AssertEquals(t, "udp", newRangePf.Protocol) + th.AssertEquals(t, "1400:1499", newRangePf.InternalPortRange) + th.AssertEquals(t, "1500:1599", newRangePf.ExternalPortRange) allPages, err := portforwarding.List(client, portforwarding.ListOpts{}, fip.ID).AllPages(context.TODO()) th.AssertNoErr(t, err) diff --git a/internal/acceptance/openstack/networking/v2/extensions/rbacpolicies/rbacpolicies.go b/internal/acceptance/openstack/networking/v2/extensions/rbacpolicies/rbacpolicies.go index 864e8fecb7..8f354c951f 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/rbacpolicies/rbacpolicies.go +++ b/internal/acceptance/openstack/networking/v2/extensions/rbacpolicies/rbacpolicies.go @@ -29,6 +29,9 @@ func CreateRBACPolicy(t *testing.T, client *gophercloud.ServiceClient, tenantID, t.Logf("Successfully created rbac_policy") th.AssertEquals(t, rbacPolicy.ObjectID, networkID) + th.AssertEquals(t, string(rbacpolicies.ActionAccessShared), string(rbacPolicy.Action)) + th.AssertEquals(t, "network", rbacPolicy.ObjectType) + th.AssertEquals(t, tenantID, rbacPolicy.TargetTenant) return rbacPolicy, nil } diff --git a/internal/acceptance/openstack/networking/v2/extensions/rbacpolicies/rbacpolicies_test.go b/internal/acceptance/openstack/networking/v2/extensions/rbacpolicies/rbacpolicies_test.go index 3bd33becd6..1c9efce343 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/rbacpolicies/rbacpolicies_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/rbacpolicies/rbacpolicies_test.go @@ -65,6 +65,7 @@ func TestRBACPolicyCRUD(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, newrbacPolicy) + th.AssertEquals(t, project2.ID, newrbacPolicy.TargetTenant) } func TestRBACPolicyList(t *testing.T) { diff --git a/internal/acceptance/openstack/networking/v2/extensions/subnetpools/subnetpools.go b/internal/acceptance/openstack/networking/v2/extensions/subnetpools/subnetpools.go index 3594e94ad4..25de4f7ab5 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/subnetpools/subnetpools.go +++ b/internal/acceptance/openstack/networking/v2/extensions/subnetpools/subnetpools.go @@ -36,6 +36,8 @@ func CreateSubnetPool(t *testing.T, client *gophercloud.ServiceClient) (*subnetp th.AssertEquals(t, subnetPool.Name, subnetPoolName) th.AssertEquals(t, subnetPool.Description, subnetPoolDescription) + th.AssertDeepEquals(t, subnetPoolPrefixes, subnetPool.Prefixes) + th.AssertEquals(t, 24, subnetPool.DefaultPrefixLen) return subnetPool, nil } diff --git a/internal/acceptance/openstack/networking/v2/extensions/taas/taas.go b/internal/acceptance/openstack/networking/v2/extensions/taas/taas.go index 3d4f3979f4..74bc9355be 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/taas/taas.go +++ b/internal/acceptance/openstack/networking/v2/extensions/taas/taas.go @@ -37,6 +37,9 @@ func CreateTapMirror(t *testing.T, client *gophercloud.ServiceClient, portID str th.AssertEquals(t, mirrorName, mirror.Name) th.AssertEquals(t, mirrorDescription, mirror.Description) + th.AssertEquals(t, portID, mirror.PortID) + th.AssertEquals(t, string(tapmirrors.MirrorTypeErspanv1), mirror.MirrorType) + th.AssertEquals(t, remoteIP, mirror.RemoteIP) t.Logf("Created Tap Mirror: %s", mirror.ID) return mirror, nil diff --git a/internal/acceptance/openstack/networking/v2/extensions/trunks/trunks.go b/internal/acceptance/openstack/networking/v2/extensions/trunks/trunks.go index 29f18dab62..f664b27c46 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/trunks/trunks.go +++ b/internal/acceptance/openstack/networking/v2/extensions/trunks/trunks.go @@ -7,6 +7,7 @@ import ( "github.com/gophercloud/gophercloud/v2" "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" "github.com/gophercloud/gophercloud/v2/openstack/networking/v2/extensions/trunks" + th "github.com/gophercloud/gophercloud/v2/testhelper" ) func CreateTrunk(t *testing.T, client *gophercloud.ServiceClient, parentPortID string, subportIDs ...string) (trunk *trunks.Trunk, err error) { @@ -32,6 +33,11 @@ func CreateTrunk(t *testing.T, client *gophercloud.ServiceClient, parentPortID s trunk, err = trunks.Create(context.TODO(), client, opts).Extract() if err == nil { t.Logf("Successfully created trunk") + + th.AssertEquals(t, trunkName, trunk.Name) + th.AssertEquals(t, "Trunk created by gophercloud", trunk.Description) + th.AssertTrue(t, trunk.AdminStateUp) + th.AssertEquals(t, parentPortID, trunk.PortID) } return } diff --git a/internal/acceptance/openstack/networking/v2/extensions/vpnaas/group_test.go b/internal/acceptance/openstack/networking/v2/extensions/vpnaas/group_test.go index 862324736f..863a8ee229 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/vpnaas/group_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/vpnaas/group_test.go @@ -56,4 +56,7 @@ func TestGroupCRUD(t *testing.T) { updatedGroup, err := endpointgroups.Update(context.TODO(), client, group.ID, updateOpts).Extract() th.AssertNoErr(t, err) tools.PrintResource(t, updatedGroup) + + th.AssertEquals(t, updatedName, updatedGroup.Name) + th.AssertEquals(t, updatedDescription, updatedGroup.Description) } diff --git a/internal/acceptance/openstack/networking/v2/extensions/vpnaas/ikepolicy_test.go b/internal/acceptance/openstack/networking/v2/extensions/vpnaas/ikepolicy_test.go index eeb573edf0..14336095d5 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/vpnaas/ikepolicy_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/vpnaas/ikepolicy_test.go @@ -60,4 +60,8 @@ func TestIKEPolicyCRUD(t *testing.T) { updatedPolicy, err := ikepolicies.Update(context.TODO(), client, policy.ID, updateOpts).Extract() th.AssertNoErr(t, err) tools.PrintResource(t, updatedPolicy) + + th.AssertEquals(t, updatedName, updatedPolicy.Name) + th.AssertEquals(t, updatedDescription, updatedPolicy.Description) + th.AssertEquals(t, 7000, updatedPolicy.Lifetime.Value) } diff --git a/internal/acceptance/openstack/networking/v2/extensions/vpnaas/ipsecpolicy_test.go b/internal/acceptance/openstack/networking/v2/extensions/vpnaas/ipsecpolicy_test.go index 74dc5a3758..f0384a6187 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/vpnaas/ipsecpolicy_test.go +++ b/internal/acceptance/openstack/networking/v2/extensions/vpnaas/ipsecpolicy_test.go @@ -51,8 +51,10 @@ func TestIPSecPolicyCRUD(t *testing.T) { policy, err = ipsecpolicies.Update(context.TODO(), client, policy.ID, updateOpts).Extract() th.AssertNoErr(t, err) tools.PrintResource(t, policy) + th.AssertEquals(t, updatedDescription, policy.Description) newPolicy, err := ipsecpolicies.Get(context.TODO(), client, policy.ID).Extract() th.AssertNoErr(t, err) tools.PrintResource(t, newPolicy) + th.AssertEquals(t, updatedDescription, newPolicy.Description) } diff --git a/internal/acceptance/openstack/networking/v2/extensions/vpnaas/vpnaas.go b/internal/acceptance/openstack/networking/v2/extensions/vpnaas/vpnaas.go index 76652134ea..2881f53752 100644 --- a/internal/acceptance/openstack/networking/v2/extensions/vpnaas/vpnaas.go +++ b/internal/acceptance/openstack/networking/v2/extensions/vpnaas/vpnaas.go @@ -35,6 +35,8 @@ func CreateService(t *testing.T, client *gophercloud.ServiceClient, routerID str t.Logf("Successfully created service %s", serviceName) th.AssertEquals(t, service.Name, serviceName) + th.AssertTrue(t, service.AdminStateUp) + th.AssertEquals(t, routerID, service.RouterID) return service, nil } @@ -74,6 +76,8 @@ func CreateIPSecPolicy(t *testing.T, client *gophercloud.ServiceClient) (*ipsecp t.Logf("Successfully created IPSec policy %s", policyName) th.AssertEquals(t, policy.Name, policyName) + th.AssertEquals(t, string(ipsecpolicies.EncryptionAlgorithmAES128), string(policy.EncryptionAlgorithm)) + th.AssertEquals(t, string(ipsecpolicies.AuthAlgorithmAESCMAC), string(policy.AuthAlgorithm)) return policy, nil } @@ -100,6 +104,9 @@ func CreateIKEPolicy(t *testing.T, client *gophercloud.ServiceClient) (*ikepolic t.Logf("Successfully created IKE policy %s", policyName) th.AssertEquals(t, policy.Name, policyName) + th.AssertEquals(t, string(ikepolicies.EncryptionAlgorithmAES128), string(policy.EncryptionAlgorithm)) + th.AssertEquals(t, string(ikepolicies.PFSGroup5), string(policy.PFS)) + th.AssertEquals(t, string(ikepolicies.AuthAlgorithmSHA256), string(policy.AuthAlgorithm)) return policy, nil } @@ -155,6 +162,8 @@ func CreateEndpointGroup(t *testing.T, client *gophercloud.ServiceClient) (*endp t.Logf("Successfully created group %s", groupName) th.AssertEquals(t, group.Name, groupName) + th.AssertEquals(t, string(endpointgroups.TypeCIDR), group.Type) + th.AssertDeepEquals(t, []string{"10.2.0.0/24", "10.3.0.0/24"}, group.Endpoints) return group, nil } @@ -182,6 +191,8 @@ func CreateEndpointGroupWithCIDR(t *testing.T, client *gophercloud.ServiceClient t.Logf("%v", group) th.AssertEquals(t, group.Name, groupName) + th.AssertEquals(t, string(endpointgroups.TypeCIDR), group.Type) + th.AssertDeepEquals(t, []string{cidr}, group.Endpoints) return group, nil } @@ -222,6 +233,8 @@ func CreateEndpointGroupWithSubnet(t *testing.T, client *gophercloud.ServiceClie t.Logf("Successfully created group %s", groupName) th.AssertEquals(t, group.Name, groupName) + th.AssertEquals(t, string(endpointgroups.TypeSubnet), group.Type) + th.AssertDeepEquals(t, []string{subnetID}, group.Endpoints) return group, nil } @@ -256,6 +269,17 @@ func CreateSiteConnection(t *testing.T, client *gophercloud.ServiceClient, ikepo t.Logf("Successfully created IPSec Site Connection %s", connectionName) th.AssertEquals(t, connection.Name, connectionName) + th.AssertEquals(t, "secret", connection.PSK) + th.AssertEquals(t, string(siteconnections.InitiatorBiDirectional), connection.Initiator) + th.AssertTrue(t, connection.AdminStateUp) + th.AssertEquals(t, ipsecpolicyID, connection.IPSecPolicyID) + th.AssertEquals(t, peerEPGroupID, connection.PeerEPGroupID) + th.AssertEquals(t, ikepolicyID, connection.IKEPolicyID) + th.AssertEquals(t, serviceID, connection.VPNServiceID) + th.AssertEquals(t, localEPGroupID, connection.LocalEPGroupID) + th.AssertEquals(t, "172.24.4.233", connection.PeerAddress) + th.AssertEquals(t, "172.24.4.233", connection.PeerID) + th.AssertEquals(t, 1500, connection.MTU) return connection, nil } diff --git a/internal/acceptance/openstack/networking/v2/networking.go b/internal/acceptance/openstack/networking/v2/networking.go index 9147c3f13b..c3874a980d 100644 --- a/internal/acceptance/openstack/networking/v2/networking.go +++ b/internal/acceptance/openstack/networking/v2/networking.go @@ -41,8 +41,9 @@ func CreateNetwork(t *testing.T, client *gophercloud.ServiceClient) (*networks.N t.Logf("Successfully created network.") - th.AssertEquals(t, network.Name, networkName) - th.AssertEquals(t, network.Description, networkDescription) + th.AssertEquals(t, networkName, network.Name) + th.AssertEquals(t, networkDescription, network.Description) + th.AssertTrue(t, network.AdminStateUp) return network, nil } @@ -108,8 +109,10 @@ func CreatePort(t *testing.T, client *gophercloud.ServiceClient, networkID, subn t.Logf("Successfully created port: %s", portName) - th.AssertEquals(t, port.Name, portName) - th.AssertEquals(t, port.Description, portDescription) + th.AssertEquals(t, portName, port.Name) + th.AssertEquals(t, portDescription, port.Description) + th.AssertTrue(t, port.AdminStateUp) + th.AssertEquals(t, networkID, port.NetworkID) return newPort, nil } @@ -146,7 +149,9 @@ func CreatePortWithNoSecurityGroup(t *testing.T, client *gophercloud.ServiceClie t.Logf("Successfully created port: %s", portName) - th.AssertEquals(t, port.Name, portName) + th.AssertEquals(t, portName, port.Name) + th.AssertFalse(t, port.AdminStateUp) + th.AssertEquals(t, networkID, port.NetworkID) return newPort, nil } @@ -187,7 +192,9 @@ func CreatePortWithoutPortSecurity(t *testing.T, client *gophercloud.ServiceClie t.Logf("Successfully created port: %s", portName) - th.AssertEquals(t, port.Name, portName) + th.AssertEquals(t, portName, port.Name) + th.AssertTrue(t, port.AdminStateUp) + th.AssertEquals(t, networkID, port.NetworkID) return newPort, nil } @@ -233,6 +240,10 @@ func CreatePortWithExtraDHCPOpts(t *testing.T, client *gophercloud.ServiceClient t.Logf("Successfully created port: %s", portName) + th.AssertEquals(t, portName, port.Name) + th.AssertTrue(t, port.AdminStateUp) + th.AssertEquals(t, networkID, port.NetworkID) + return port, nil } @@ -268,8 +279,10 @@ func CreatePortWithMultipleFixedIPs(t *testing.T, client *gophercloud.ServiceCli t.Logf("Successfully created port: %s", portName) - th.AssertEquals(t, port.Name, portName) - th.AssertEquals(t, port.Description, portDescription) + th.AssertEquals(t, portName, port.Name) + th.AssertEquals(t, portDescription, port.Description) + th.AssertTrue(t, port.AdminStateUp) + th.AssertEquals(t, networkID, port.NetworkID) if len(port.FixedIPs) != 2 { t.Fatalf("Failed to create a port with two fixed IPs: %s", portName) @@ -311,10 +324,13 @@ func CreateSubnetWithCIDR(t *testing.T, client *gophercloud.ServiceClient, netwo t.Logf("Successfully created subnet.") - th.AssertEquals(t, subnet.Name, subnetName) - th.AssertEquals(t, subnet.Description, subnetDescription) - th.AssertEquals(t, subnet.GatewayIP, subnetGateway) - th.AssertEquals(t, subnet.CIDR, subnetCIDR) + th.AssertEquals(t, subnetName, subnet.Name) + th.AssertEquals(t, subnetDescription, subnet.Description) + th.AssertEquals(t, subnetGateway, subnet.GatewayIP) + th.AssertEquals(t, subnetCIDR, subnet.CIDR) + th.AssertEquals(t, networkID, subnet.NetworkID) + th.AssertEquals(t, 4, subnet.IPVersion) + th.AssertFalse(t, subnet.EnableDHCP) return subnet, nil } @@ -349,11 +365,14 @@ func CreateSubnetWithServiceTypes(t *testing.T, client *gophercloud.ServiceClien t.Logf("Successfully created subnet.") - th.AssertEquals(t, subnet.Name, subnetName) - th.AssertEquals(t, subnet.Description, subnetDescription) - th.AssertEquals(t, subnet.GatewayIP, subnetGateway) - th.AssertEquals(t, subnet.CIDR, subnetCIDR) - th.AssertDeepEquals(t, subnet.ServiceTypes, serviceTypes) + th.AssertEquals(t, subnetName, subnet.Name) + th.AssertEquals(t, subnetDescription, subnet.Description) + th.AssertEquals(t, subnetGateway, subnet.GatewayIP) + th.AssertEquals(t, subnetCIDR, subnet.CIDR) + th.AssertEquals(t, networkID, subnet.NetworkID) + th.AssertEquals(t, 4, subnet.IPVersion) + th.AssertFalse(t, subnet.EnableDHCP) + th.AssertDeepEquals(t, serviceTypes, subnet.ServiceTypes) return subnet, nil } @@ -384,9 +403,12 @@ func CreateSubnetWithDefaultGateway(t *testing.T, client *gophercloud.ServiceCli t.Logf("Successfully created subnet.") - th.AssertEquals(t, subnet.Name, subnetName) - th.AssertEquals(t, subnet.GatewayIP, defaultGateway) - th.AssertEquals(t, subnet.CIDR, subnetCIDR) + th.AssertEquals(t, subnetName, subnet.Name) + th.AssertEquals(t, defaultGateway, subnet.GatewayIP) + th.AssertEquals(t, subnetCIDR, subnet.CIDR) + th.AssertEquals(t, networkID, subnet.NetworkID) + th.AssertEquals(t, 4, subnet.IPVersion) + th.AssertFalse(t, subnet.EnableDHCP) return subnet, nil } @@ -425,9 +447,12 @@ func CreateSubnetWithNoGateway(t *testing.T, client *gophercloud.ServiceClient, t.Logf("Successfully created subnet.") - th.AssertEquals(t, subnet.Name, subnetName) + th.AssertEquals(t, subnetName, subnet.Name) th.AssertEquals(t, "", subnet.GatewayIP) - th.AssertEquals(t, subnet.CIDR, subnetCIDR) + th.AssertEquals(t, subnetCIDR, subnet.CIDR) + th.AssertEquals(t, networkID, subnet.NetworkID) + th.AssertEquals(t, 4, subnet.IPVersion) + th.AssertFalse(t, subnet.EnableDHCP) return subnet, nil } @@ -456,8 +481,12 @@ func CreateSubnetWithSubnetPool(t *testing.T, client *gophercloud.ServiceClient, t.Logf("Successfully created subnet.") - th.AssertEquals(t, subnet.Name, subnetName) - th.AssertEquals(t, subnet.CIDR, subnetCIDR) + th.AssertEquals(t, subnetName, subnet.Name) + th.AssertEquals(t, subnetCIDR, subnet.CIDR) + th.AssertEquals(t, networkID, subnet.NetworkID) + th.AssertEquals(t, 4, subnet.IPVersion) + th.AssertFalse(t, subnet.EnableDHCP) + th.AssertEquals(t, subnetPoolID, subnet.SubnetPoolID) return subnet, nil } @@ -484,7 +513,11 @@ func CreateSubnetWithSubnetPoolNoCIDR(t *testing.T, client *gophercloud.ServiceC t.Logf("Successfully created subnet.") - th.AssertEquals(t, subnet.Name, subnetName) + th.AssertEquals(t, subnetName, subnet.Name) + th.AssertEquals(t, networkID, subnet.NetworkID) + th.AssertEquals(t, 4, subnet.IPVersion) + th.AssertFalse(t, subnet.EnableDHCP) + th.AssertEquals(t, subnetPoolID, subnet.SubnetPoolID) return subnet, nil } @@ -513,7 +546,11 @@ func CreateSubnetWithSubnetPoolPrefixlen(t *testing.T, client *gophercloud.Servi t.Logf("Successfully created subnet.") - th.AssertEquals(t, subnet.Name, subnetName) + th.AssertEquals(t, subnetName, subnet.Name) + th.AssertEquals(t, networkID, subnet.NetworkID) + th.AssertEquals(t, 4, subnet.IPVersion) + th.AssertFalse(t, subnet.EnableDHCP) + th.AssertEquals(t, subnetPoolID, subnet.SubnetPoolID) return subnet, nil } diff --git a/internal/acceptance/openstack/networking/v2/networks_test.go b/internal/acceptance/openstack/networking/v2/networks_test.go index fe641b3f8b..1c8b12f355 100644 --- a/internal/acceptance/openstack/networking/v2/networks_test.go +++ b/internal/acceptance/openstack/networking/v2/networks_test.go @@ -153,6 +153,7 @@ func TestNetworksPortSecurityCRUD(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, networkWithExtensions) + th.AssertTrue(t, networkWithExtensions.PortSecurityEnabled) } func TestNetworksRevision(t *testing.T) { diff --git a/internal/acceptance/openstack/networking/v2/ports_test.go b/internal/acceptance/openstack/networking/v2/ports_test.go index 4729862fc0..2667f4a20f 100644 --- a/internal/acceptance/openstack/networking/v2/ports_test.go +++ b/internal/acceptance/openstack/networking/v2/ports_test.go @@ -415,6 +415,7 @@ func TestPortsPortSecurityCRUD(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, portWithExt) + th.AssertTrue(t, portWithExt.PortSecurityEnabled) } func TestPortsWithExtraDHCPOptsCRUD(t *testing.T) { @@ -466,6 +467,7 @@ func TestPortsWithExtraDHCPOptsCRUD(t *testing.T) { th.AssertNoErr(t, err) tools.PrintResource(t, newPort) + th.AssertEquals(t, newPortName, newPort.Name) } func TestPortsTrustedVIFCRUD(t *testing.T) { @@ -519,6 +521,10 @@ func TestPortsTrustedVIFCRUD(t *testing.T) { if err != nil { t.Fatalf("Unable to update port: %v", err) } + if portWithExt.PortTrustedVIF == nil { + t.Fatal("Expected PortTrustedVIF to be non-nil after update") + } + th.AssertTrue(t, *portWithExt.PortTrustedVIF) } func TestPortsRevision(t *testing.T) { diff --git a/internal/acceptance/openstack/orchestration/v1/orchestration.go b/internal/acceptance/openstack/orchestration/v1/orchestration.go index e6245ad83d..c143dafbaf 100644 --- a/internal/acceptance/openstack/orchestration/v1/orchestration.go +++ b/internal/acceptance/openstack/orchestration/v1/orchestration.go @@ -78,7 +78,13 @@ func CreateStack(t *testing.T, client *gophercloud.ServiceClient) (*stacks.Retri } newStack, err := stacks.Get(context.TODO(), client, stackName, stack.ID).Extract() - return newStack, err + if err != nil { + return nil, err + } + + th.AssertEquals(t, stackName, newStack.Name) + + return newStack, nil } // DeleteStack deletes a stack via its ID. diff --git a/internal/acceptance/openstack/sharedfilesystems/v2/securityservices.go b/internal/acceptance/openstack/sharedfilesystems/v2/securityservices.go index 413095a6e2..e781f332cf 100644 --- a/internal/acceptance/openstack/sharedfilesystems/v2/securityservices.go +++ b/internal/acceptance/openstack/sharedfilesystems/v2/securityservices.go @@ -7,6 +7,7 @@ import ( "github.com/gophercloud/gophercloud/v2" "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" "github.com/gophercloud/gophercloud/v2/openstack/sharedfilesystems/v2/securityservices" + th "github.com/gophercloud/gophercloud/v2/testhelper" ) // CreateSecurityService will create a security service with a random name. An @@ -31,6 +32,10 @@ func CreateSecurityService(t *testing.T, client *gophercloud.ServiceClient) (*se return securityService, err } + th.AssertEquals(t, securityServiceName, securityService.Name) + th.AssertEquals(t, securityServiceDescription, securityService.Description) + th.AssertEquals(t, "kerberos", securityService.Type) + return securityService, nil } diff --git a/internal/acceptance/openstack/sharedfilesystems/v2/sharenetworks.go b/internal/acceptance/openstack/sharedfilesystems/v2/sharenetworks.go index 86d074058c..ab81ea28ac 100644 --- a/internal/acceptance/openstack/sharedfilesystems/v2/sharenetworks.go +++ b/internal/acceptance/openstack/sharedfilesystems/v2/sharenetworks.go @@ -8,6 +8,7 @@ import ( "github.com/gophercloud/gophercloud/v2/internal/acceptance/clients" "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" "github.com/gophercloud/gophercloud/v2/openstack/sharedfilesystems/v2/sharenetworks" + th "github.com/gophercloud/gophercloud/v2/testhelper" ) // CreateShareNetwork will create a share network with a random name. An @@ -37,6 +38,11 @@ func CreateShareNetwork(t *testing.T, client *gophercloud.ServiceClient) (*share return shareNetwork, err } + th.AssertEquals(t, shareNetworkName, shareNetwork.Name) + th.AssertEquals(t, "This is a shared network", shareNetwork.Description) + th.AssertEquals(t, choices.NetworkID, shareNetwork.NeutronNetID) + th.AssertEquals(t, choices.SubnetID, shareNetwork.NeutronSubnetID) + return shareNetwork, nil } diff --git a/internal/acceptance/openstack/sharedfilesystems/v2/shares.go b/internal/acceptance/openstack/sharedfilesystems/v2/shares.go index eacceebf1e..e5b9a78e64 100644 --- a/internal/acceptance/openstack/sharedfilesystems/v2/shares.go +++ b/internal/acceptance/openstack/sharedfilesystems/v2/shares.go @@ -12,6 +12,7 @@ import ( "github.com/gophercloud/gophercloud/v2" "github.com/gophercloud/gophercloud/v2/openstack/sharedfilesystems/v2/messages" "github.com/gophercloud/gophercloud/v2/openstack/sharedfilesystems/v2/shares" + th "github.com/gophercloud/gophercloud/v2/testhelper" ) // CreateShare will create a share with a name, and a size of 1Gb. An @@ -48,6 +49,11 @@ func CreateShare(t *testing.T, client *gophercloud.ServiceClient, optShareType . return share, err } + th.AssertEquals(t, "My Test Share", share.Name) + th.AssertEquals(t, "My Test Description", share.Description) + th.AssertEquals(t, "NFS", share.ShareProto) + th.AssertEquals(t, 1, share.Size) + return share, nil } diff --git a/internal/acceptance/openstack/sharedfilesystems/v2/sharetypes.go b/internal/acceptance/openstack/sharedfilesystems/v2/sharetypes.go index 69e0a4ea3c..69b46d444c 100644 --- a/internal/acceptance/openstack/sharedfilesystems/v2/sharetypes.go +++ b/internal/acceptance/openstack/sharedfilesystems/v2/sharetypes.go @@ -7,6 +7,7 @@ import ( "github.com/gophercloud/gophercloud/v2" "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" "github.com/gophercloud/gophercloud/v2/openstack/sharedfilesystems/v2/sharetypes" + th "github.com/gophercloud/gophercloud/v2/testhelper" ) // CreateShareType will create a share type with a random name. An @@ -34,6 +35,9 @@ func CreateShareType(t *testing.T, client *gophercloud.ServiceClient) (*sharetyp return shareType, err } + th.AssertEquals(t, shareTypeName, shareType.Name) + th.AssertFalse(t, shareType.IsPublic) + return shareType, nil } diff --git a/internal/acceptance/openstack/sharedfilesystems/v2/snapshots.go b/internal/acceptance/openstack/sharedfilesystems/v2/snapshots.go index 9c5ccb7949..4a34ac7111 100644 --- a/internal/acceptance/openstack/sharedfilesystems/v2/snapshots.go +++ b/internal/acceptance/openstack/sharedfilesystems/v2/snapshots.go @@ -10,6 +10,7 @@ import ( "github.com/gophercloud/gophercloud/v2" "github.com/gophercloud/gophercloud/v2/internal/acceptance/tools" "github.com/gophercloud/gophercloud/v2/openstack/sharedfilesystems/v2/snapshots" + th "github.com/gophercloud/gophercloud/v2/testhelper" ) // CreateSnapshot will create a snapshot from the share ID with a name. An error will @@ -37,6 +38,10 @@ func CreateSnapshot(t *testing.T, client *gophercloud.ServiceClient, shareID str return snapshot, err } + th.AssertEquals(t, "My Test Snapshot", snapshot.Name) + th.AssertEquals(t, "My Test Description", snapshot.Description) + th.AssertEquals(t, shareID, snapshot.ShareID) + return snapshot, nil } diff --git a/internal/acceptance/openstack/workflow/v2/crontrigger.go b/internal/acceptance/openstack/workflow/v2/crontrigger.go index 109807c81c..289cd4ee44 100644 --- a/internal/acceptance/openstack/workflow/v2/crontrigger.go +++ b/internal/acceptance/openstack/workflow/v2/crontrigger.go @@ -32,7 +32,9 @@ func CreateCronTrigger(t *testing.T, client *gophercloud.ServiceClient, workflow return crontrigger, err } t.Logf("Cron trigger created: %s", crontriggerName) - th.AssertEquals(t, crontrigger.Name, crontriggerName) + th.AssertEquals(t, crontriggerName, crontrigger.Name) + th.AssertEquals(t, workflow.ID, crontrigger.WorkflowID) + th.AssertEquals(t, "0 0 1 1 *", crontrigger.Pattern) return crontrigger, nil } diff --git a/internal/acceptance/openstack/workflow/v2/execution.go b/internal/acceptance/openstack/workflow/v2/execution.go index 9a3eccaa9d..672222fe4d 100644 --- a/internal/acceptance/openstack/workflow/v2/execution.go +++ b/internal/acceptance/openstack/workflow/v2/execution.go @@ -14,11 +14,12 @@ import ( // CreateExecution creates an execution for the given workflow. func CreateExecution(t *testing.T, client *gophercloud.ServiceClient, workflow *workflows.Workflow) (*executions.Execution, error) { + executionID := tools.RandomString("execution_", 5) executionDescription := tools.RandomString("execution_", 5) t.Logf("Attempting to create execution: %s", executionDescription) createOpts := executions.CreateOpts{ - ID: executionDescription, + ID: executionID, WorkflowID: workflow.ID, WorkflowNamespace: workflow.Namespace, Description: executionDescription, @@ -33,7 +34,9 @@ func CreateExecution(t *testing.T, client *gophercloud.ServiceClient, workflow * t.Logf("Execution created: %s", executionDescription) - th.AssertEquals(t, execution.Description, executionDescription) + th.AssertEquals(t, executionDescription, execution.Description) + th.AssertEquals(t, workflow.ID, execution.WorkflowID) + th.AssertEquals(t, workflow.Namespace, execution.WorkflowNamespace) t.Logf("Wait for execution status SUCCESS: %s", executionDescription) th.AssertNoErr(t, tools.WaitFor(func(ctx context.Context) (bool, error) { diff --git a/internal/acceptance/openstack/workflow/v2/workflow.go b/internal/acceptance/openstack/workflow/v2/workflow.go index ea67739eac..3d9ce81134 100644 --- a/internal/acceptance/openstack/workflow/v2/workflow.go +++ b/internal/acceptance/openstack/workflow/v2/workflow.go @@ -57,6 +57,8 @@ func CreateWorkflow(t *testing.T, client *gophercloud.ServiceClient) (*workflows t.Logf("Workflow created: %s", workflowName) th.AssertEquals(t, workflowName, workflow.Name) + th.AssertEquals(t, "some-namespace", workflow.Namespace) + th.AssertEquals(t, "private", workflow.Scope) return &workflow, nil } From e25ed42480835bcce0692b55326b035e0764d874 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 29 May 2026 09:53:37 +0000 Subject: [PATCH 411/429] build(deps): bump golang.org/x/crypto from 0.51.0 to 0.52.0 Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.51.0 to 0.52.0. - [Commits](https://github.com/golang/crypto/compare/v0.51.0...v0.52.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-version: 0.52.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index f2f4598ea8..43aa487759 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.25.0 require ( go.yaml.in/yaml/v3 v3.0.4 - golang.org/x/crypto v0.51.0 + golang.org/x/crypto v0.52.0 ) -require golang.org/x/sys v0.44.0 // indirect +require golang.org/x/sys v0.45.0 // indirect diff --git a/go.sum b/go.sum index d85ec14b2c..e19b7b10b6 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI= -golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8= -golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ= -golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= +golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= +golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= +golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4= golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= From 1a8a6bdffc8a2bdff0b9b88273fdd7a60d3a38ca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 29 May 2026 09:55:14 +0000 Subject: [PATCH 412/429] build(deps): bump github/codeql-action from 4.35.5 to 4.36.0 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.35.5 to 4.36.0. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/9e0d7b8d25671d64c341c19c0152d693099fb5ba...7211b7c8077ea37d8641b6271f6a365a22a5fbfa) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 4.36.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql-analysis.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yaml b/.github/workflows/codeql-analysis.yaml index b3f415da50..119834669f 100644 --- a/.github/workflows/codeql-analysis.yaml +++ b/.github/workflows/codeql-analysis.yaml @@ -29,12 +29,12 @@ jobs: cache: true - name: Initialize CodeQL - uses: github/codeql-action/init@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5 + uses: github/codeql-action/init@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5 + uses: github/codeql-action/autobuild@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5 + uses: github/codeql-action/analyze@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 From ecfd2c9649292523ce4cafb2a726631093467fd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Fri, 29 May 2026 08:58:17 +0200 Subject: [PATCH 413/429] docs: relax one-operation-per-PR rule Soften the PR scope guidance across contributor documentation to allow grouping related operations in a single PR. This better reflects current practice now that we have stable branches where non-breaking features are backported. --- docs/STYLEGUIDE.md | 5 ++--- docs/contributor-tutorial/step-02-issues.md | 5 +++-- .../step-05-pull-requests.md | 20 ++++++++----------- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/docs/STYLEGUIDE.md b/docs/STYLEGUIDE.md index fb09b72f6a..8d3b426d28 100644 --- a/docs/STYLEGUIDE.md +++ b/docs/STYLEGUIDE.md @@ -28,9 +28,8 @@ [Pending #PRNUM] tag once the PR has been updated with the merged, dependent PR. That will let reviewers know it is ready to review. -- A PR should be small. Even if you intend on implementing an entire - service, a PR should only be one route of that service - (e.g. create server or get server, but not both). +- A PR should be focused. Group related operations together, but avoid + mixing unrelated changes in a single PR. - Unless explicitly asked, do not squash commits in the middle of a review; only append. It makes it difficult for the reviewer to see what's changed from one diff --git a/docs/contributor-tutorial/step-02-issues.md b/docs/contributor-tutorial/step-02-issues.md index 3c1937612b..62d8fc7094 100644 --- a/docs/contributor-tutorial/step-02-issues.md +++ b/docs/contributor-tutorial/step-02-issues.md @@ -87,8 +87,9 @@ supports the OpenStack projects proper. ### Adding a Missing API Suite -Adding support to a missing suite of API calls will require more than one Pull -Request. However, you can use a single issue for all PRs. +Adding support to a missing suite of API calls can be done in a single Pull +Request or broken into multiple PRs. Either way, you can use a single issue +to track the work. Examples of issues which track the addition of a missing API suite are: diff --git a/docs/contributor-tutorial/step-05-pull-requests.md b/docs/contributor-tutorial/step-05-pull-requests.md index 5f29a938e4..0d074b00e4 100644 --- a/docs/contributor-tutorial/step-05-pull-requests.md +++ b/docs/contributor-tutorial/step-05-pull-requests.md @@ -37,9 +37,6 @@ If you're adding a single field, then a single Pull Request is also fine. See [#662](https://github.com/gophercloud/gophercloud/pull/662) as an example of this. -If you plan to add more than one missing field, you will need to open a Pull -Request for _each_ field. - ### Adding a Single API Call Single API calls can also be submitted as a single Pull Request. See @@ -49,14 +46,13 @@ this. ### Adding a Suite of API Calls If you're adding support for a "suite" of API calls (meaning: Create, Update, -Delete, Get), then you will need to create one Pull Request for _each_ call. +Delete, Get), you can group related operations into a single Pull Request. +Different API suites (e.g. servers and flavors) should be submitted as separate +PRs. -The following Pull Requests are good examples of how to do this: +The following Pull Request is a good example of adding an entire API suite: -* https://github.com/gophercloud/gophercloud/pull/584 -* https://github.com/gophercloud/gophercloud/pull/586 -* https://github.com/gophercloud/gophercloud/pull/587 -* https://github.com/gophercloud/gophercloud/pull/594 +* https://github.com/gophercloud/gophercloud/pull/3701 You can also use the provided [template](/docs/contributor-tutorial/.template) as it contains a lot of the repeated boiler plate code seen in each resource. @@ -66,9 +62,9 @@ the work and will require further rounds of review to fix. ### Adding an Entire OpenStack Project -To add an entire OpenStack project, you must break each set of API calls into -individual Pull Requests. Implementing an entire project can be thought of as -implementing multiple API suites. +To add an entire OpenStack project, break it into Pull Requests by API suite. +Implementing an entire project can be thought of as implementing multiple API +suites. An example of this can be seen from the Pull Requests referenced in [#723](https://github.com/gophercloud/gophercloud/issues/723). From 07787e8ae185cec7d13484d17824c0a1921a5639 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Fri, 29 May 2026 09:03:16 +0200 Subject: [PATCH 414/429] Add AGENTS.md Add a reference guide for AI coding agents. Unfortunately, claude still doesn't understand standards and we need to symlink AGENTS.md to CLAUDE.md. --- AGENTS.md | 215 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ CLAUDE.md | 1 + 2 files changed, 216 insertions(+) create mode 100644 AGENTS.md create mode 120000 CLAUDE.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..1b5a20580b --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,215 @@ +# AGENTS.md + +Quick reference guide for AI coding agents working in the Gophercloud repository. + +**Project:** Gophercloud - Go SDK for OpenStack services +**Module:** `github.com/gophercloud/gophercloud/v2` +**Language:** Go (see version in [go.mod](go.mod)) +**Stable Branch:** v2 (main development on `main`) + +## Build, Test & Lint Commands + +### Running Tests + +**Unit tests (default):** +```bash +make unit +``` + +**Unit tests with verbose output:** +```bash +go test -v ./... +``` + +**Run single test by name:** +```bash +cd openstack/compute/v2/servers +go test -run TestCreateServer ./... +``` + +**Coverage:** +```bash +make coverage +``` + +**Acceptance tests (requires live OpenStack - may incur charges):** +```bash +make acceptance # All services +make acceptance-compute # Specific service +``` + +**Run single acceptance test:** +```bash +cd internal/acceptance/openstack/compute/v2 +go test -timeout 60m -tags "acceptance" -run TestServersList +``` + +### Linting & Formatting + +```bash +make lint # Run golangci-lint in container (Docker/Podman) +make format # Run gofmt with simplify flag +``` + +**Note:** If lint fails with SELinux errors, run: +```bash +chcon -Rt svirt_sandbox_file_t . +chcon -Rt svirt_sandbox_file_t ~/.cache/golangci-lint +``` + +## Code Style Guidelines + +### Import Organization + +Group imports in this order (separated by blank lines): +1. Standard library (alphabetically) +2. External dependencies (alphabetically) +3. Gophercloud internal packages (alphabetically) + +Example: +```go +import ( + "context" + "encoding/json" + "fmt" + + "github.com/gophercloud/gophercloud/v2" + "github.com/gophercloud/gophercloud/v2/pagination" +) +``` + +### File Structure + +Standard package structure under `openstack////`: +- **`requests.go`** - HTTP request functions and OptsBuilder types +- **`results.go`** - Response structs and extraction methods +- **`urls.go`** - Endpoint URL construction helpers +- **`microversions.go`** - Microversion-specific types (when needed) +- **`testing/`** - Unit tests with HTTP mocking + +### Naming Conventions + +**Result receivers and variables:** +- Result method receiver: `r` +- Unmarshalled variable: `s` +- Request function return value: `r` + +**OptsBuilder pattern:** +- Interface name: `OptsBuilder` (e.g., `CreateOptsBuilder`, `ListOptsBuilder`) +- Method for request body: `ToMap` (e.g., `ToServerCreateMap`) +- Method for query string: `ToQuery` (e.g., `ToServerListQuery`) + +Example: +```go +type CreateOptsBuilder interface { + ToServerCreateMap() (map[string]interface{}, error) +} + +type CreateOpts struct { + Name string `json:"name"` +} + +func (opts CreateOpts) ToServerCreateMap() (map[string]interface{}, error) { + return gophercloud.BuildRequestBody(opts, "server") +} +``` + +### Types & Pointers + +- **New response fields (microversions):** Use pointer types to allow nil-checking +- **Optional request fields:** Always use `omitempty` JSON tag +- **Required fields:** No `omitempty` tag + +### Error Handling + +- Use `gophercloud.Result` and `gophercloud.ErrResult` types +- Extract errors with `.ExtractErr()` method +- Return errors directly, don't wrap unless adding context + +### Documentation + +- **All struct fields** must have GoDoc comments +- **Microversion-dependent fields** must document required version in GoDoc +- **Package documentation** goes in `doc.go` +- Follow existing comment style in similar packages + +Example: +```go +// This requires the client to be set to microversion 2.52 or later. +// Tags is the list of server tags. +Tags []string `json:"tags,omitempty"` +``` + +### Testing Requirements + +**Unit tests (in `testing/` subdirectory):** +- Use `testhelper` package to mock HTTP +- `fakeServer := th.SetupHTTP()` / `defer fakeServer.Teardown()` for setup/teardown +- `fakeServer.Mux.HandleFunc()` to register mock endpoints +- Test ALL options (every field in request/response structs) +- Use assertion helpers from `testhelper/convenience.go` (value assertions) and `testhelper/http_responses.go` (HTTP request assertions) +- `Assert*` variants are fatal (`t.Fatalf`), `Check*` variants are non-fatal (`t.Errorf`) +- Assertion argument order is **expected first, actual second**: `th.AssertEquals(t, "expected_value", actual.Field)` + +**Acceptance tests:** +- Located in `internal/acceptance/openstack//` +- Test against real OpenStack APIs +- Cover all operation variants + +## Microversions + +Set microversion on ServiceClient: +```go +client.Microversion = "2.52" +``` + +**Implementation rules:** +- **New request fields:** Must use `omitempty` + document microversion +- **New response fields:** Add as pointer types +- **Changed response types:** Create new structs in `microversions.go` + +See `docs/MICROVERSIONS.md` for details. + +## Pull Request Requirements + +**Before opening PR:** +1. **GitHub issue must exist** with core contributor approval +2. **PR description must include:** + - `For #` reference + - Link(s) to OpenStack source code (non-master branch) proving validity +3. **Keep PRs focused:** Group related operations together; avoid mixing unrelated changes +4. **Tests required:** Unit tests AND acceptance tests covering all options +5. **Work-in-progress:** Prefix title with `[wip]` until ready +6. **Dependencies:** Prefix with `[Pending #PRNUM]` if depends on another PR + +**During review:** +- Do NOT squash commits (only append) +- Follow existing patterns in codebase +- Address all reviewer feedback + +## Common Patterns + +**Context usage:** +Always pass `context.Context` to API operations: +```go +servers.List(client, opts).EachPage(ctx, func(ctx context.Context, page pagination.Page) (bool, error) { + // ... +}) +``` + +**Pagination:** +```go +pager := servers.List(client, servers.ListOpts{}) +err := pager.EachPage(ctx, func(ctx context.Context, page pagination.Page) (bool, error) { + servers, err := servers.ExtractServers(page) + // process... + return true, nil +}) +``` + +## Key Reminders + +- Module path: `github.com/gophercloud/gophercloud/v2` (note the `/v2`) +- Gophercloud does NOT validate microversion compatibility +- PRs target `main` branch, not `v2` +- Documentation auto-generated from GoDoc comments diff --git a/CLAUDE.md b/CLAUDE.md new file mode 120000 index 0000000000..47dc3e3d86 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file From 95a7f62bd8288ed9667ede6f59b70a4a10eefcd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Mon, 8 Jun 2026 10:27:15 +0200 Subject: [PATCH 415/429] CI: skip failing Magnum and Zaqar master jobs Also restore Aetos that is now passing. --- script/configure-required-github-jobs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/script/configure-required-github-jobs b/script/configure-required-github-jobs index 5f431c65fb..f74a56f87d 100755 --- a/script/configure-required-github-jobs +++ b/script/configure-required-github-jobs @@ -55,9 +55,8 @@ declare -A EXPECTED_SETTINGS=( # their workflow has an `on: merge_group` trigger. Add entries using the exact # name format: "" (with resolved matrix values). SKIP_CHECKS=( - # FIXME(stephenfin): Re-enable this once [1] merges - # [1] https://review.opendev.org/c/openstack/project-config/+/983728 - "Aetos on OpenStack master" + "Magnum on OpenStack master" + "Zaqar on OpenStack master" "finish" # coveralls parallel-finish job, not a test gate ) From fb5d233e8558553660068dbff22d7d6899d68e51 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Jun 2026 09:11:04 +0000 Subject: [PATCH 416/429] build(deps): bump github/codeql-action from 4.36.0 to 4.36.1 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.36.0 to 4.36.1. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/7211b7c8077ea37d8641b6271f6a365a22a5fbfa...87557b9c84dde89fdd9b10e88954ac2f4248e463) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 4.36.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql-analysis.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yaml b/.github/workflows/codeql-analysis.yaml index 119834669f..c80277f903 100644 --- a/.github/workflows/codeql-analysis.yaml +++ b/.github/workflows/codeql-analysis.yaml @@ -29,12 +29,12 @@ jobs: cache: true - name: Initialize CodeQL - uses: github/codeql-action/init@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 + uses: github/codeql-action/init@87557b9c84dde89fdd9b10e88954ac2f4248e463 # v4.36.1 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 + uses: github/codeql-action/autobuild@87557b9c84dde89fdd9b10e88954ac2f4248e463 # v4.36.1 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0 + uses: github/codeql-action/analyze@87557b9c84dde89fdd9b10e88954ac2f4248e463 # v4.36.1 From 4252174108a1c9431dcd58b22051ff8beb40798d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 09:08:53 +0000 Subject: [PATCH 417/429] build(deps): bump github/codeql-action from 4.36.1 to 4.36.2 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.36.1 to 4.36.2. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/87557b9c84dde89fdd9b10e88954ac2f4248e463...8aad20d150bbac5944a9f9d289da16a4b0d87c1e) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 4.36.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql-analysis.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yaml b/.github/workflows/codeql-analysis.yaml index c80277f903..575076be67 100644 --- a/.github/workflows/codeql-analysis.yaml +++ b/.github/workflows/codeql-analysis.yaml @@ -29,12 +29,12 @@ jobs: cache: true - name: Initialize CodeQL - uses: github/codeql-action/init@87557b9c84dde89fdd9b10e88954ac2f4248e463 # v4.36.1 + uses: github/codeql-action/init@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@87557b9c84dde89fdd9b10e88954ac2f4248e463 # v4.36.1 + uses: github/codeql-action/autobuild@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@87557b9c84dde89fdd9b10e88954ac2f4248e463 # v4.36.1 + uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 From 45070c2d7a875150f18b72c18e128096a0709840 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Jun 2026 09:08:08 +0000 Subject: [PATCH 418/429] build(deps): bump golang.org/x/crypto from 0.52.0 to 0.53.0 Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.52.0 to 0.53.0. - [Commits](https://github.com/golang/crypto/compare/v0.52.0...v0.53.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-version: 0.53.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 43aa487759..e6cd1fb0a5 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.25.0 require ( go.yaml.in/yaml/v3 v3.0.4 - golang.org/x/crypto v0.52.0 + golang.org/x/crypto v0.53.0 ) -require golang.org/x/sys v0.45.0 // indirect +require golang.org/x/sys v0.46.0 // indirect diff --git a/go.sum b/go.sum index e19b7b10b6..0616a587ff 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,10 @@ go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= -golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= -golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= -golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4= -golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk= +golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto= +golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio= +golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= +golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc= +golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 2782e25e0d8ef971af9c93b6d0280b3798c42c51 Mon Sep 17 00:00:00 2001 From: abhijith-darshan Date: Thu, 18 Jun 2026 11:13:16 +0200 Subject: [PATCH 419/429] dns: add AllProjects and SudoTenantID header support to zones.List Add ListOptsHeadersBuilder optional interface and AllProjects/SudoTenantID fields to ListOpts, allowing admin users to enumerate zones across all projects via X-Auth-All-Projects header, and to impersonate a tenant via X-Auth-Sudo-Tenant-ID header. List() uses a type assertion to remain backward compatible with existing ListOptsBuilder implementations. Functional tests require admin credentials via clients.RequireAdmin. Signed-off-by: abhijith-darshan --- .../acceptance/openstack/dns/v2/zones_test.go | 27 ++++++++++++++++ openstack/dns/v2/zones/doc.go | 20 ++++++++++++ openstack/dns/v2/zones/requests.go | 31 ++++++++++++++++++- .../dns/v2/zones/testing/fixtures_test.go | 13 ++++++++ .../dns/v2/zones/testing/requests_test.go | 13 ++++++++ 5 files changed, 103 insertions(+), 1 deletion(-) diff --git a/internal/acceptance/openstack/dns/v2/zones_test.go b/internal/acceptance/openstack/dns/v2/zones_test.go index f7ddd69fec..9984989bdd 100644 --- a/internal/acceptance/openstack/dns/v2/zones_test.go +++ b/internal/acceptance/openstack/dns/v2/zones_test.go @@ -53,3 +53,30 @@ func TestZonesCRUD(t *testing.T) { th.AssertEquals(t, newZone.Description, description) th.AssertEquals(t, 3600, newZone.TTL) } + +func TestZonesListWithAllProjects(t *testing.T) { + clients.RequireAdmin(t) + + client, err := clients.NewDNSV2Client() + th.AssertNoErr(t, err) + + zone, err := CreateZone(t, client) + th.AssertNoErr(t, err) + defer DeleteZone(t, client, zone) + + listOpts := zones.ListOpts{AllProjects: true} + allPages, err := zones.List(client, listOpts).AllPages(context.TODO()) + th.AssertNoErr(t, err) + + allZones, err := zones.ExtractZones(allPages) + th.AssertNoErr(t, err) + + var found bool + for _, z := range allZones { + if zone.Name == z.Name { + found = true + } + } + + th.AssertTrue(t, found) +} diff --git a/openstack/dns/v2/zones/doc.go b/openstack/dns/v2/zones/doc.go index 6bd7d98cb5..4537eda5d4 100644 --- a/openstack/dns/v2/zones/doc.go +++ b/openstack/dns/v2/zones/doc.go @@ -22,6 +22,26 @@ Example to List Zones fmt.Printf("%+v\n", zone) } +Example to List Zones Across All Projects + + listOpts := zones.ListOpts{ + AllProjects: true, + } + + allPages, err := zones.List(dnsClient, listOpts).AllPages(context.TODO()) + if err != nil { + panic(err) + } + + allZones, err := zones.ExtractZones(allPages) + if err != nil { + panic(err) + } + + for _, zone := range allZones { + fmt.Printf("%+v\n", zone) + } + Example to Create a Zone createOpts := zones.CreateOpts{ diff --git a/openstack/dns/v2/zones/requests.go b/openstack/dns/v2/zones/requests.go index b0049a9148..6be0f27772 100644 --- a/openstack/dns/v2/zones/requests.go +++ b/openstack/dns/v2/zones/requests.go @@ -12,6 +12,11 @@ type ListOptsBuilder interface { ToZoneListQuery() (string, error) } +// ListOptsHeadersBuilder allows extensions to add additional headers to the List request. +type ListOptsHeadersBuilder interface { + ToZoneListHeaders() (map[string]string, error) +} + // ListOpts allows the filtering and sorting of paginated collections through // the API. Filtering is achieved by passing in struct field values that map to // the server attributes you want to see returned. Marker and Limit are used @@ -32,6 +37,12 @@ type ListOpts struct { Status string `q:"status"` TTL int `q:"ttl"` Type string `q:"type"` + + // All projects header + AllProjects bool `h:"X-Auth-All-Projects"` + + // Sudo tenant ID + SudoTenantID bool `h:"X-Auth-Sudo-Tenant-ID"` } // ToZoneListQuery formats a ListOpts into a query string. @@ -40,19 +51,37 @@ func (opts ListOpts) ToZoneListQuery() (string, error) { return q.String(), err } +// ToZoneListHeaders formats a ListOpts into header parameters. +func (opts ListOpts) ToZoneListHeaders() (map[string]string, error) { + return gophercloud.BuildHeaders(opts) +} + // List implements a zone List request. func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { url := baseURL(client) + var h map[string]string + if opts != nil { query, err := opts.ToZoneListQuery() if err != nil { return pagination.Pager{Err: err} } url += query + + // Check if opts implements the optional headers interface + if optsWithHeaders, ok := opts.(ListOptsHeadersBuilder); ok { + h, err = optsWithHeaders.ToZoneListHeaders() + if err != nil { + return pagination.Pager{Err: err} + } + } } - return pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page { + + pager := pagination.NewPager(client, url, func(r pagination.PageResult) pagination.Page { return ZonePage{pagination.LinkedPageBase{PageResult: r}} }) + pager.Headers = h + return pager } // Get returns information about a zone, given its ID. diff --git a/openstack/dns/v2/zones/testing/fixtures_test.go b/openstack/dns/v2/zones/testing/fixtures_test.go index 8a7b12a09f..120a6818ad 100644 --- a/openstack/dns/v2/zones/testing/fixtures_test.go +++ b/openstack/dns/v2/zones/testing/fixtures_test.go @@ -153,6 +153,19 @@ func HandleListSuccessfully(t *testing.T, fakeServer th.FakeServer) { }) } +// HandleListAllProjectsSuccessfully configures the test server to respond to a List request +// with the X-Auth-All-Projects header set. +func HandleListAllProjectsSuccessfully(t *testing.T, fakeServer th.FakeServer) { + fakeServer.Mux.HandleFunc("/zones", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + th.TestHeader(t, r, "X-Auth-All-Projects", "true") + + w.Header().Add("Content-Type", "application/json") + fmt.Fprint(w, ListOutput) + }) +} + // HandleGetSuccessfully configures the test server to respond to a List request. func HandleGetSuccessfully(t *testing.T, fakeServer th.FakeServer) { fakeServer.Mux.HandleFunc("/zones/a86dba58-0043-4cc6-a1bb-69d5e86f3ca3", func(w http.ResponseWriter, r *http.Request) { diff --git a/openstack/dns/v2/zones/testing/requests_test.go b/openstack/dns/v2/zones/testing/requests_test.go index f425f051b8..a5bb2ccbfb 100644 --- a/openstack/dns/v2/zones/testing/requests_test.go +++ b/openstack/dns/v2/zones/testing/requests_test.go @@ -44,6 +44,19 @@ func TestListAllPages(t *testing.T) { th.CheckEquals(t, 2, len(allZones)) } +func TestListWithAllProjects(t *testing.T) { + fakeServer := th.SetupHTTP() + defer fakeServer.Teardown() + HandleListAllProjectsSuccessfully(t, fakeServer) + + opts := zones.ListOpts{AllProjects: true} + allPages, err := zones.List(client.ServiceClient(fakeServer), opts).AllPages(context.TODO()) + th.AssertNoErr(t, err) + allZones, err := zones.ExtractZones(allPages) + th.AssertNoErr(t, err) + th.CheckEquals(t, 2, len(allZones)) +} + func TestGet(t *testing.T) { fakeServer := th.SetupHTTP() defer fakeServer.Teardown() From e33eaf4ad5e341b56648e5c88882e23ab4adb90b Mon Sep 17 00:00:00 2001 From: abhijith-darshan Date: Fri, 19 Jun 2026 15:53:23 +0200 Subject: [PATCH 420/429] dns: fix SudoTenantID type in zones ListOpts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change SudoTenantID from bool to string — it carries a tenant UUID, not a boolean flag. --- openstack/dns/v2/zones/requests.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openstack/dns/v2/zones/requests.go b/openstack/dns/v2/zones/requests.go index 6be0f27772..f234766f9f 100644 --- a/openstack/dns/v2/zones/requests.go +++ b/openstack/dns/v2/zones/requests.go @@ -41,8 +41,8 @@ type ListOpts struct { // All projects header AllProjects bool `h:"X-Auth-All-Projects"` - // Sudo tenant ID - SudoTenantID bool `h:"X-Auth-Sudo-Tenant-ID"` + // SudoTenantID impersonates the given project. + SudoTenantID string `h:"X-Auth-Sudo-Tenant-ID"` } // ToZoneListQuery formats a ListOpts into a query string. From 1ac7e443fe2390c4c4896f335ccffe6fdb8e005b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Jun 2026 09:07:14 +0000 Subject: [PATCH 421/429] build(deps): bump actions/checkout from 6.0.2 to 7.0.0 Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.2 to 7.0.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/de0fac2e4500dabe0009e67214ff5f5447ce83dd...9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql-analysis.yaml | 2 +- .github/workflows/ensure-labels.yaml | 2 +- .github/workflows/functional-baremetal.yaml | 2 +- .github/workflows/functional-basic.yaml | 2 +- .github/workflows/functional-blockstorage.yaml | 2 +- .github/workflows/functional-compute.yaml | 2 +- .github/workflows/functional-containerinfra.yaml | 2 +- .github/workflows/functional-dns.yaml | 2 +- .github/workflows/functional-fwaas_v2.yaml | 2 +- .github/workflows/functional-identity.yaml | 2 +- .github/workflows/functional-image.yaml | 2 +- .github/workflows/functional-keymanager.yaml | 2 +- .github/workflows/functional-loadbalancer.yaml | 2 +- .github/workflows/functional-messaging.yaml | 2 +- .github/workflows/functional-metric.yaml | 2 +- .github/workflows/functional-networking.yaml | 2 +- .github/workflows/functional-objectstorage.yaml | 2 +- .github/workflows/functional-orchestration.yaml | 2 +- .github/workflows/functional-placement.yaml | 2 +- .github/workflows/functional-sharedfilesystems.yaml | 2 +- .github/workflows/functional-workflow.yaml | 2 +- .github/workflows/lint.yaml | 2 +- .github/workflows/semver.yaml | 2 +- .github/workflows/unit.yaml | 2 +- .github/workflows/zizmor.yaml | 2 +- 25 files changed, 25 insertions(+), 25 deletions(-) diff --git a/.github/workflows/codeql-analysis.yaml b/.github/workflows/codeql-analysis.yaml index c80277f903..5653e2e80f 100644 --- a/.github/workflows/codeql-analysis.yaml +++ b/.github/workflows/codeql-analysis.yaml @@ -18,7 +18,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false diff --git a/.github/workflows/ensure-labels.yaml b/.github/workflows/ensure-labels.yaml index 4df98ce2bc..10be137be0 100644 --- a/.github/workflows/ensure-labels.yaml +++ b/.github/workflows/ensure-labels.yaml @@ -13,7 +13,7 @@ jobs: issues: write runs-on: ubuntu-latest steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - uses: micnncim/action-label-syncer@3abd5ab72fda571e69fffd97bd4e0033dd5f495c # v1.3.0 diff --git a/.github/workflows/functional-baremetal.yaml b/.github/workflows/functional-baremetal.yaml index 5b2b84d9d1..19a55101de 100644 --- a/.github/workflows/functional-baremetal.yaml +++ b/.github/workflows/functional-baremetal.yaml @@ -25,7 +25,7 @@ jobs: name: Ironic on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false diff --git a/.github/workflows/functional-basic.yaml b/.github/workflows/functional-basic.yaml index 4f19727a8e..781d0f6db8 100644 --- a/.github/workflows/functional-basic.yaml +++ b/.github/workflows/functional-basic.yaml @@ -25,7 +25,7 @@ jobs: name: basic tests on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false diff --git a/.github/workflows/functional-blockstorage.yaml b/.github/workflows/functional-blockstorage.yaml index 7e0ba900dd..6ec0cc9c15 100644 --- a/.github/workflows/functional-blockstorage.yaml +++ b/.github/workflows/functional-blockstorage.yaml @@ -25,7 +25,7 @@ jobs: name: Cinder on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false diff --git a/.github/workflows/functional-compute.yaml b/.github/workflows/functional-compute.yaml index 481ff8199f..50edc26ed5 100644 --- a/.github/workflows/functional-compute.yaml +++ b/.github/workflows/functional-compute.yaml @@ -25,7 +25,7 @@ jobs: name: Nova on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false diff --git a/.github/workflows/functional-containerinfra.yaml b/.github/workflows/functional-containerinfra.yaml index f429102f07..a6d9d1617a 100644 --- a/.github/workflows/functional-containerinfra.yaml +++ b/.github/workflows/functional-containerinfra.yaml @@ -34,7 +34,7 @@ jobs: name: Magnum on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false diff --git a/.github/workflows/functional-dns.yaml b/.github/workflows/functional-dns.yaml index dc13f66fa5..75a1bc08e6 100644 --- a/.github/workflows/functional-dns.yaml +++ b/.github/workflows/functional-dns.yaml @@ -25,7 +25,7 @@ jobs: name: Designate on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false diff --git a/.github/workflows/functional-fwaas_v2.yaml b/.github/workflows/functional-fwaas_v2.yaml index 0868b67daf..4a4a81972d 100644 --- a/.github/workflows/functional-fwaas_v2.yaml +++ b/.github/workflows/functional-fwaas_v2.yaml @@ -29,7 +29,7 @@ jobs: name: FWaaS_v2 on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false diff --git a/.github/workflows/functional-identity.yaml b/.github/workflows/functional-identity.yaml index 3bb9d7ac46..0cd48ea457 100644 --- a/.github/workflows/functional-identity.yaml +++ b/.github/workflows/functional-identity.yaml @@ -25,7 +25,7 @@ jobs: name: Keystone on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false diff --git a/.github/workflows/functional-image.yaml b/.github/workflows/functional-image.yaml index 3fc2c83562..213372d748 100644 --- a/.github/workflows/functional-image.yaml +++ b/.github/workflows/functional-image.yaml @@ -25,7 +25,7 @@ jobs: name: Glance on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false diff --git a/.github/workflows/functional-keymanager.yaml b/.github/workflows/functional-keymanager.yaml index 5d7ebd3d6c..94c856b158 100644 --- a/.github/workflows/functional-keymanager.yaml +++ b/.github/workflows/functional-keymanager.yaml @@ -25,7 +25,7 @@ jobs: name: Barbican on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false diff --git a/.github/workflows/functional-loadbalancer.yaml b/.github/workflows/functional-loadbalancer.yaml index 62103ce327..a3355516bb 100644 --- a/.github/workflows/functional-loadbalancer.yaml +++ b/.github/workflows/functional-loadbalancer.yaml @@ -34,7 +34,7 @@ jobs: name: Octavia on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false diff --git a/.github/workflows/functional-messaging.yaml b/.github/workflows/functional-messaging.yaml index 38a350e451..3df50d278e 100644 --- a/.github/workflows/functional-messaging.yaml +++ b/.github/workflows/functional-messaging.yaml @@ -25,7 +25,7 @@ jobs: name: Zaqar on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false diff --git a/.github/workflows/functional-metric.yaml b/.github/workflows/functional-metric.yaml index 387b9e06d0..50b350c70e 100644 --- a/.github/workflows/functional-metric.yaml +++ b/.github/workflows/functional-metric.yaml @@ -19,7 +19,7 @@ jobs: name: Aetos on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false diff --git a/.github/workflows/functional-networking.yaml b/.github/workflows/functional-networking.yaml index 6d4522ac64..a8fb047b57 100644 --- a/.github/workflows/functional-networking.yaml +++ b/.github/workflows/functional-networking.yaml @@ -25,7 +25,7 @@ jobs: name: Neutron on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false diff --git a/.github/workflows/functional-objectstorage.yaml b/.github/workflows/functional-objectstorage.yaml index 92c2e9ee3a..3adddecf09 100644 --- a/.github/workflows/functional-objectstorage.yaml +++ b/.github/workflows/functional-objectstorage.yaml @@ -25,7 +25,7 @@ jobs: name: Swift on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false diff --git a/.github/workflows/functional-orchestration.yaml b/.github/workflows/functional-orchestration.yaml index d4a189f2bd..dddf874c0b 100644 --- a/.github/workflows/functional-orchestration.yaml +++ b/.github/workflows/functional-orchestration.yaml @@ -25,7 +25,7 @@ jobs: name: Heat on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false diff --git a/.github/workflows/functional-placement.yaml b/.github/workflows/functional-placement.yaml index 93c642a112..fd0082924a 100644 --- a/.github/workflows/functional-placement.yaml +++ b/.github/workflows/functional-placement.yaml @@ -25,7 +25,7 @@ jobs: name: Placement on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false diff --git a/.github/workflows/functional-sharedfilesystems.yaml b/.github/workflows/functional-sharedfilesystems.yaml index caf5aa09f9..1d6051df05 100644 --- a/.github/workflows/functional-sharedfilesystems.yaml +++ b/.github/workflows/functional-sharedfilesystems.yaml @@ -25,7 +25,7 @@ jobs: name: Manila on OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false diff --git a/.github/workflows/functional-workflow.yaml b/.github/workflows/functional-workflow.yaml index e78aec2438..267032b010 100644 --- a/.github/workflows/functional-workflow.yaml +++ b/.github/workflows/functional-workflow.yaml @@ -28,7 +28,7 @@ jobs: name: Mistral on Deploy OpenStack ${{ matrix.name }} steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 37108b22f2..0fe6b8cd48 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 diff --git a/.github/workflows/semver.yaml b/.github/workflows/semver.yaml index 67e0b7889c..2ab445a758 100644 --- a/.github/workflows/semver.yaml +++ b/.github/workflows/semver.yaml @@ -13,7 +13,7 @@ jobs: analyze: runs-on: ubuntu-latest steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 ref: ${{ github.event.pull_request.head.sha }} diff --git a/.github/workflows/unit.yaml b/.github/workflows/unit.yaml index 69b5466ee5..50e9f6c935 100644 --- a/.github/workflows/unit.yaml +++ b/.github/workflows/unit.yaml @@ -15,7 +15,7 @@ jobs: fail-fast: false steps: - name: Checkout Gophercloud - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Setup Go diff --git a/.github/workflows/zizmor.yaml b/.github/workflows/zizmor.yaml index 8258e9c0f5..ff0814e629 100644 --- a/.github/workflows/zizmor.yaml +++ b/.github/workflows/zizmor.yaml @@ -20,7 +20,7 @@ jobs: contents: read steps: - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false From d82294ffedd56e2af91f43415506f127af1df332 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Thu, 25 Jun 2026 17:22:26 +0200 Subject: [PATCH 422/429] CI: mark failing CI jobs as not required --- script/configure-required-github-jobs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/script/configure-required-github-jobs b/script/configure-required-github-jobs index f74a56f87d..fe6acfb28c 100755 --- a/script/configure-required-github-jobs +++ b/script/configure-required-github-jobs @@ -55,8 +55,8 @@ declare -A EXPECTED_SETTINGS=( # their workflow has an `on: merge_group` trigger. Add entries using the exact # name format: "" (with resolved matrix values). SKIP_CHECKS=( - "Magnum on OpenStack master" - "Zaqar on OpenStack master" + "Magnum on OpenStack master" # https://github.com/gophercloud/gophercloud/issues/3818 + "Neutron on OpenStack master" # https://github.com/gophercloud/gophercloud/issues/3817 "finish" # coveralls parallel-finish job, not a test gate ) From 62cc9b318f0eb3d409a8e27a18a9289cbc248058 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Fri, 26 Jun 2026 09:29:42 +0200 Subject: [PATCH 423/429] ci: add functional CI workflow for Zun (container) Add a new GitHub Actions workflow that runs Zun acceptance tests against three OpenStack releases (master, gazpacho, epoxy). The workflow enables the Zun DevStack plugin and runs the existing acceptance-container Makefile target. The t.Skip calls that were unconditionally skipping both capsule tests are removed so the tests actually run in CI. --- .github/workflows/functional-container.yaml | 106 ++++++++++++++++++ .../openstack/container/v1/capsules_test.go | 4 - 2 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/functional-container.yaml diff --git a/.github/workflows/functional-container.yaml b/.github/workflows/functional-container.yaml new file mode 100644 index 0000000000..1b07f8375a --- /dev/null +++ b/.github/workflows/functional-container.yaml @@ -0,0 +1,106 @@ +name: functional-container +on: + merge_group: + pull_request: + schedule: + - cron: '0 0 */3 * *' +jobs: + functional-container: + permissions: + contents: read + strategy: + fail-fast: false + matrix: + include: + - name: "master" + openstack_version: "master" + ubuntu_version: "24.04" + - name: "gazpacho" + openstack_version: "stable/2026.1" + ubuntu_version: "24.04" + - name: "epoxy" + openstack_version: "stable/2025.1" + ubuntu_version: "24.04" + runs-on: ubuntu-${{ matrix.ubuntu_version }} + name: Zun on OpenStack ${{ matrix.name }} + steps: + - name: Checkout Gophercloud + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + + - name: Check changed files + uses: ./.github/actions/file-filter + id: changed-files + with: + patterns: | + openstack/auth_env.go + openstack/client.go + openstack/endpoint.go + openstack/endpoint_location.go + openstack/config/provider_client.go + openstack/utils/choose_version.go + openstack/utils/discovery.go + **container/** + .github/workflows/functional-container.yaml + + - name: Skip tests for unrelated changed-files + if: ${{ ! fromJSON(steps.changed-files.outputs.matches) }} + run: | + echo "No relevant files changed - skipping tests for ${{ matrix.name }}" + echo "TESTS_SKIPPED=true" >> $GITHUB_ENV + + - name: Deploy devstack + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} + uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 # v0.19 + with: + branch: ${{ matrix.openstack_version }} + enable_workaround_docker_io: false + conf_overrides: | + enable_plugin zun https://github.com/openstack/zun ${{ matrix.openstack_version }} + enable_plugin devstack-plugin-container https://github.com/openstack/devstack-plugin-container ${{ matrix.openstack_version }} + enable_plugin kuryr-libnetwork https://github.com/openstack/kuryr-libnetwork ${{ matrix.openstack_version }} + KURYR_CONFIG_DIR=/etc/kuryr-libnetwork + ZUN_DRIVER=docker + ZUN_CAPSULE_DRIVER=docker + ZUN_DB_TYPE=sql + ENABLE_CONTAINERD_CRI=true + enabled_services: "zun-api,zun-compute,zun-wsproxy,openstack-cli-server" + + - name: Checkout go + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 + with: + go-version-file: 'go.mod' + cache: true + + - name: Run Gophercloud acceptance tests + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} + run: | + source ${{ github.workspace }}/script/stackenv + make acceptance-container + echo "TESTS_RUN=true" >> $GITHUB_ENV + env: + DEVSTACK_PATH: ${{ github.workspace }}/devstack + OS_BRANCH: ${{ matrix.openstack_version }} + + - name: Generate logs on failure + run: ./script/collectlogs + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} + + - name: Upload logs artifacts on failure + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: functional-container-${{ matrix.name }}-${{ github.run_id }} + path: /tmp/devstack-logs/* + + - name: Set job status + run: | + if [[ "$TESTS_SKIPPED" == "true" || "$TESTS_RUN" == "true" ]]; then + echo "Job completed successfully (either ran tests or skipped appropriately)" + exit 0 + else + echo "Job failed - neither tests ran nor were properly skipped" + exit 1 + fi diff --git a/internal/acceptance/openstack/container/v1/capsules_test.go b/internal/acceptance/openstack/container/v1/capsules_test.go index 9873facf2c..57227ef5e1 100644 --- a/internal/acceptance/openstack/container/v1/capsules_test.go +++ b/internal/acceptance/openstack/container/v1/capsules_test.go @@ -13,8 +13,6 @@ import ( ) func TestCapsuleBase(t *testing.T) { - t.Skip("Currently failing in OpenLab") - clients.SkipRelease(t, "stable/mitaka") clients.SkipRelease(t, "stable/newton") clients.SkipRelease(t, "stable/ocata") @@ -64,8 +62,6 @@ func TestCapsuleBase(t *testing.T) { } func TestCapsuleV132(t *testing.T) { - t.Skip("Currently failing in OpenLab") - clients.SkipRelease(t, "stable/mitaka") clients.SkipRelease(t, "stable/newton") clients.SkipRelease(t, "stable/ocata") From 5fff5e8e7f84b508209ffec8b310295629f8155f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Fri, 26 Jun 2026 11:21:51 +0200 Subject: [PATCH 424/429] ci(container): fix sandbox image for capsule creation The default sandbox image 'kubernetes/pause' no longer exists on Docker Hub (zero tags available). Override it with 'registry.k8s.io/pause:3.9' via post-config in zun.conf. --- .github/workflows/functional-container.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/functional-container.yaml b/.github/workflows/functional-container.yaml index 1b07f8375a..36f179e0a1 100644 --- a/.github/workflows/functional-container.yaml +++ b/.github/workflows/functional-container.yaml @@ -65,6 +65,9 @@ jobs: ZUN_CAPSULE_DRIVER=docker ZUN_DB_TYPE=sql ENABLE_CONTAINERD_CRI=true + [[post-config|\$ZUN_CONF]] + [DEFAULT] + sandbox_image = registry.k8s.io/pause:3.9 enabled_services: "zun-api,zun-compute,zun-wsproxy,openstack-cli-server" - name: Checkout go From 90a0a93a2737c942df5fe0d7726414de72ee1ba6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Fri, 26 Jun 2026 10:40:18 +0200 Subject: [PATCH 425/429] Fix microversion header for Zun (application-container) Zun's API validates that the OpenStack-API-Version header uses 'container' as the service type, but gophercloud was sending 'application-container' (the service catalog type). Map it to 'container', matching the pattern used for other services like cinder (volume) and magnum (container-infra). --- service_client.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/service_client.go b/service_client.go index 015c3f2339..0b14f84c86 100644 --- a/service_client.go +++ b/service_client.go @@ -133,6 +133,9 @@ func (client *ServiceClient) setMicroversionHeader(opts *RequestOpts) { case "container-infrastructure-management", "container-infrastructure", "container-infra": // magnum should accept container-infrastructure-management but (as of Epoxy) does not serviceType = "container-infra" + case "application-container": + // zun expects "container" in the OpenStack-API-Version header + serviceType = "container" } if client.Type != "" { From 7b7ccafd6ce2f22e3f94c70dc61c900a87ba4975 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Fri, 26 Jun 2026 11:35:40 +0200 Subject: [PATCH 426/429] ci(container): skip Zun master (upstream bug) Zun master has a regression where capsule creation fails with a CapsuleInitContainer/CapsuleContainer type mismatch caused by the new CoercedList.__add__ in oslo.versionedobjects master enforcing element type coercion on list concatenation. Skip the master job via configure-required-github-jobs until the upstream fix lands. https://bugs.launchpad.net/zun/+bug/2158372 --- script/configure-required-github-jobs | 1 + 1 file changed, 1 insertion(+) diff --git a/script/configure-required-github-jobs b/script/configure-required-github-jobs index fe6acfb28c..0ec9251491 100755 --- a/script/configure-required-github-jobs +++ b/script/configure-required-github-jobs @@ -57,6 +57,7 @@ declare -A EXPECTED_SETTINGS=( SKIP_CHECKS=( "Magnum on OpenStack master" # https://github.com/gophercloud/gophercloud/issues/3818 "Neutron on OpenStack master" # https://github.com/gophercloud/gophercloud/issues/3817 + "Zun on OpenStack master" # https://bugs.launchpad.net/zun/+bug/2158372 "finish" # coveralls parallel-finish job, not a test gate ) From e03dbc0a4ca726a9c3c062cd702b10e12fcd3c16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Fri, 26 Jun 2026 12:21:30 +0200 Subject: [PATCH 427/429] ci: add GOTESTFLAGS variable to Makefile Add a GOTESTFLAGS variable (empty by default) to allow passing extra flags to go test in acceptance targets. This is useful for passing -short to skip long-running tests that require infrastructure not available in CI (e.g. KVM for Trove instance creation). --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9041e0c4fd..cffb8e248b 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,7 @@ undefine GOFLAGS GOLANGCI_LINT_VERSION?=v2.12.1 GOTESTSUM_VERSION?=v1.13.0 GO_TEST?=go run gotest.tools/gotestsum@$(GOTESTSUM_VERSION) --format testname -- +GOTESTFLAGS?= TIMEOUT := "60m" ifeq ($(shell command -v podman 2> /dev/null),) @@ -71,7 +72,7 @@ acceptance-containerinfra: .PHONY: acceptance-containerinfra acceptance-db: - $(GO_TEST) -timeout $(TIMEOUT) -tags "fixtures acceptance" ./internal/acceptance/openstack/db/... + $(GO_TEST) -timeout $(TIMEOUT) $(GOTESTFLAGS) -tags "fixtures acceptance" ./internal/acceptance/openstack/db/... .PHONY: acceptance-db acceptance-dns: From fb608dee67307ce131e9badec51eb0ab4b3fa50d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Andr=C3=A9?= Date: Fri, 26 Jun 2026 12:21:38 +0200 Subject: [PATCH 428/429] ci: add functional CI workflow for Trove (db) Add a new GitHub Actions workflow that runs Trove acceptance tests against three OpenStack releases (master, gazpacho, epoxy). The workflow enables the Trove DevStack plugin and runs the existing acceptance-db Makefile target with -short to skip tests that require KVM (instance creation). The stackenv script is updated to dynamically detect the Trove datastore type and version from the service catalog and export them as OS_DB_DATASTORE_TYPE and OS_DB_DATASTORE_VERSION. --- .github/workflows/functional-db.yaml | 105 +++++++++++++++++++++++++++ script/stackenv | 11 +++ 2 files changed, 116 insertions(+) create mode 100644 .github/workflows/functional-db.yaml diff --git a/.github/workflows/functional-db.yaml b/.github/workflows/functional-db.yaml new file mode 100644 index 0000000000..677f41a0dc --- /dev/null +++ b/.github/workflows/functional-db.yaml @@ -0,0 +1,105 @@ +name: functional-db +on: + merge_group: + pull_request: + schedule: + - cron: '0 0 */3 * *' +jobs: + functional-db: + permissions: + contents: read + strategy: + fail-fast: false + matrix: + include: + - name: "master" + openstack_version: "master" + ubuntu_version: "24.04" + - name: "gazpacho" + openstack_version: "stable/2026.1" + ubuntu_version: "24.04" + - name: "epoxy" + openstack_version: "stable/2025.1" + ubuntu_version: "24.04" + runs-on: ubuntu-${{ matrix.ubuntu_version }} + name: Trove on OpenStack ${{ matrix.name }} + steps: + - name: Checkout Gophercloud + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + + - name: Check changed files + uses: ./.github/actions/file-filter + id: changed-files + with: + patterns: | + openstack/auth_env.go + openstack/client.go + openstack/endpoint.go + openstack/endpoint_location.go + openstack/config/provider_client.go + openstack/utils/choose_version.go + openstack/utils/discovery.go + **db** + .github/workflows/functional-db.yaml + + - name: Skip tests for unrelated changed-files + if: ${{ ! fromJSON(steps.changed-files.outputs.matches) }} + run: | + echo "No relevant files changed - skipping tests for ${{ matrix.name }}" + echo "TESTS_SKIPPED=true" >> $GITHUB_ENV + + - name: Prepare trove-tempest-plugin + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} + run: | + sudo mkdir -p /opt/stack + sudo chown -R $(whoami) /opt/stack + git clone https://github.com/openstack/trove-tempest-plugin.git /opt/stack/trove-tempest-plugin + + - name: Deploy devstack + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} + uses: gophercloud/devstack-action@60ca1042045c0c9e3e001c64575d381654ffcba1 # v0.19 + with: + branch: ${{ matrix.openstack_version }} + conf_overrides: | + enable_plugin trove https://github.com/openstack/trove ${{ matrix.openstack_version }} + enabled_services: "trove,tr-api,tr-tmgr,tr-cond,openstack-cli-server" + + - name: Checkout go + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 + with: + go-version-file: 'go.mod' + cache: true + + - name: Run Gophercloud acceptance tests + if: ${{ fromJSON(steps.changed-files.outputs.matches) }} + run: | + source ${{ github.workspace }}/script/stackenv + make acceptance-db GOTESTFLAGS=-short + echo "TESTS_RUN=true" >> $GITHUB_ENV + env: + DEVSTACK_PATH: ${{ github.workspace }}/devstack + OS_BRANCH: ${{ matrix.openstack_version }} + + - name: Generate logs on failure + run: ./script/collectlogs + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} + + - name: Upload logs artifacts on failure + if: ${{ failure() && fromJSON(steps.changed-files.outputs.matches) }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: functional-db-${{ matrix.name }}-${{ github.run_id }} + path: /tmp/devstack-logs/* + + - name: Set job status + run: | + if [[ "$TESTS_SKIPPED" == "true" || "$TESTS_RUN" == "true" ]]; then + echo "Job completed successfully (either ran tests or skipped appropriately)" + exit 0 + else + echo "Job failed - neither tests ran nor were properly skipped" + exit 1 + fi diff --git a/script/stackenv b/script/stackenv index 6e2a32ebeb..0dffd4ed1e 100644 --- a/script/stackenv +++ b/script/stackenv @@ -59,6 +59,17 @@ export OS_FLAVOR_ID="$_FLAVOR_ID" export OS_FLAVOR_ID_RESIZE="$_FLAVOR_ALT_ID" EOL +if _=$(openstack service list | grep database); then + _DB_DATASTORE_TYPE=$(openstack datastore list -f value -c Name | head -1) + if [[ -n "$_DB_DATASTORE_TYPE" ]]; then + _DB_DATASTORE_VERSION=$(openstack datastore version list "$_DB_DATASTORE_TYPE" -f value -c Name | head -1) + cat >> "openrc" < Date: Fri, 26 Jun 2026 12:27:25 +0200 Subject: [PATCH 429/429] test(db): fix configurations acceptance test Fix assertion argument order to follow the project convention of expected first, actual second. Switch from Update (PATCH) to Replace (PUT) for modifying the configuration group name and description, since the Trove PATCH endpoint only merges configuration values and does not update metadata fields. --- .../openstack/db/v1/configurations_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/acceptance/openstack/db/v1/configurations_test.go b/internal/acceptance/openstack/db/v1/configurations_test.go index 51058e16ba..4531bb13ba 100644 --- a/internal/acceptance/openstack/db/v1/configurations_test.go +++ b/internal/acceptance/openstack/db/v1/configurations_test.go @@ -49,19 +49,19 @@ func TestConfigurationsCRUD(t *testing.T) { } tools.PrintResource(t, readCgroup) - th.AssertEquals(t, readCgroup.Name, createOpts.Name) - th.AssertEquals(t, readCgroup.Description, createOpts.Description) + th.AssertEquals(t, createOpts.Name, readCgroup.Name) + th.AssertEquals(t, createOpts.Description, readCgroup.Description) // TODO: verify datastore //th.AssertDeepEquals(t, readCgroup.Datastore, datastore) // Update cgroup newCgroupName := "New configuration name" - newCgroupDescription := "" + newCgroupDescription := "Updated description" updateOpts := configurations.UpdateOpts{ Name: newCgroupName, Description: &newCgroupDescription, } - err = configurations.Update(context.TODO(), client, cgroup.ID, updateOpts).ExtractErr() + err = configurations.Replace(context.TODO(), client, cgroup.ID, updateOpts).ExtractErr() th.AssertNoErr(t, err) newCgroup, err := configurations.Get(context.TODO(), client, cgroup.ID).Extract() @@ -70,8 +70,8 @@ func TestConfigurationsCRUD(t *testing.T) { } tools.PrintResource(t, newCgroup) - th.AssertEquals(t, newCgroup.Name, newCgroupName) - th.AssertEquals(t, newCgroup.Description, newCgroupDescription) + th.AssertEquals(t, newCgroupName, newCgroup.Name) + th.AssertEquals(t, newCgroupDescription, newCgroup.Description) err = configurations.Delete(context.TODO(), client, cgroup.ID).ExtractErr() if err != nil {