From 315f2335b9b40014645235d08720f43733c60f19 Mon Sep 17 00:00:00 2001 From: yylt <34183906+yylt@users.noreply.github.com> Date: Fri, 16 Apr 2021 13:22:23 +0800 Subject: [PATCH 01/26] heat/stack support show hidden option (#2104) Co-authored-by: yang.yang --- openstack/orchestration/v1/stacks/requests.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openstack/orchestration/v1/stacks/requests.go b/openstack/orchestration/v1/stacks/requests.go index bf480f06d8..a17cbd5f98 100644 --- a/openstack/orchestration/v1/stacks/requests.go +++ b/openstack/orchestration/v1/stacks/requests.go @@ -253,6 +253,9 @@ type ListOpts struct { // ShowNested set to `true` to include nested stacks in the list. ShowNested bool `q:"show_nested"` + // ShowHidden set to `true` to include hiddened stacks in the list. + ShowHidden bool `q:"show_hidden"` + // Tags lists stacks that contain one or more simple string tags. Tags string `q:"tags"` From 1f929efd30f55f81960334a623b96d7a65bba4f3 Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Thu, 15 Apr 2021 23:24:19 -0600 Subject: [PATCH 02/26] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea4ca7539e..898a3239b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## 0.18.0 (Unreleased) +IMPROVEMENTS + +* Added `orchestration/v1/stacks.ListOpts.ShowHidden` [GH-2104](https://github.com/gophercloud/gophercloud/pull/2104) + ## 0.17.0 (April 9, 2021) IMPROVEMENTS From 6a3f4b1ddeb05348ab48350e0a4d8a9b49cbd73d Mon Sep 17 00:00:00 2001 From: Sergey Putko Date: Fri, 23 Apr 2021 17:58:54 +0300 Subject: [PATCH 03/26] Fix doc (#2143) --- .../networking/v2/extensions/networkipavailabilities/doc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openstack/networking/v2/extensions/networkipavailabilities/doc.go b/openstack/networking/v2/extensions/networkipavailabilities/doc.go index 9109473693..faadaa2227 100644 --- a/openstack/networking/v2/extensions/networkipavailabilities/doc.go +++ b/openstack/networking/v2/extensions/networkipavailabilities/doc.go @@ -9,7 +9,7 @@ Example of Listing NetworkIPAvailabilities panic(err) } - allAvailabilities, err := subnetpools.ExtractSubnetPools(allPages) + allAvailabilities, err := networkipavailabilities.ExtractNetworkIPAvailabilities(allPages) if err != nil { panic(err) } From dbea4fcfb05bb26cfbeb896099845cc07a27df4f Mon Sep 17 00:00:00 2001 From: Parasyris Nikolaos Date: Thu, 29 Apr 2021 19:00:46 +0200 Subject: [PATCH 04/26] Add SCTP protocol on octavia listener (#2149) --- openstack/loadbalancer/v2/listeners/requests.go | 14 ++++++++------ openstack/loadbalancer/v2/listeners/results.go | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/openstack/loadbalancer/v2/listeners/requests.go b/openstack/loadbalancer/v2/listeners/requests.go index 07fa26848d..08a1f5823e 100644 --- a/openstack/loadbalancer/v2/listeners/requests.go +++ b/openstack/loadbalancer/v2/listeners/requests.go @@ -12,11 +12,13 @@ type Protocol string // Supported attributes for create/update operations. const ( - ProtocolTCP Protocol = "TCP" - ProtocolUDP Protocol = "UDP" - ProtocolPROXY Protocol = "PROXY" - ProtocolHTTP Protocol = "HTTP" - ProtocolHTTPS Protocol = "HTTPS" + ProtocolTCP Protocol = "TCP" + ProtocolUDP Protocol = "UDP" + ProtocolPROXY Protocol = "PROXY" + ProtocolHTTP Protocol = "HTTP" + ProtocolHTTPS Protocol = "HTTPS" + // Protocol SCTP requires octavia microversion 2.23 + ProtocolSCTP Protocol = "SCTP" ProtocolTerminatedHTTPS Protocol = "TERMINATED_HTTPS" ) @@ -88,7 +90,7 @@ type CreateOpts struct { // The load balancer on which to provision this listener. LoadbalancerID string `json:"loadbalancer_id,omitempty"` - // The protocol - can either be TCP, HTTP, HTTPS or TERMINATED_HTTPS. + // The protocol - can either be TCP, SCTP, HTTP, HTTPS or TERMINATED_HTTPS. Protocol Protocol `json:"protocol" required:"true"` // The port on which to listen for client traffic. diff --git a/openstack/loadbalancer/v2/listeners/results.go b/openstack/loadbalancer/v2/listeners/results.go index 3271c6ae05..1d5761fb84 100644 --- a/openstack/loadbalancer/v2/listeners/results.go +++ b/openstack/loadbalancer/v2/listeners/results.go @@ -27,7 +27,7 @@ type Listener struct { // Human-readable description for the Listener. Description string `json:"description"` - // The protocol to loadbalance. A valid value is TCP, HTTP, or HTTPS. + // The protocol to loadbalance. A valid value is TCP, SCTP, HTTP, HTTPS or TERMINATED_HTTPS. Protocol string `json:"protocol"` // The port on which to listen to client traffic that is associated with the From 3e9de207d89a5fe520fc155bf8edd44e91a0fff8 Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Thu, 29 Apr 2021 11:01:40 -0600 Subject: [PATCH 05/26] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 898a3239b7..0a62c6e2fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ IMPROVEMENTS * Added `orchestration/v1/stacks.ListOpts.ShowHidden` [GH-2104](https://github.com/gophercloud/gophercloud/pull/2104) +* Added `loadbalancer/v2/listeners.ProtocolSCTP` [GH-2149](https://github.com/gophercloud/gophercloud/pull/2149) ## 0.17.0 (April 9, 2021) From 2e59567c532702dfa24b670f5bcd58ff1d93635c Mon Sep 17 00:00:00 2001 From: Parasyris Nikolaos Date: Thu, 29 Apr 2021 19:23:53 +0200 Subject: [PATCH 06/26] Add support for loadbalancer listener tls versions (#2150) --- .../openstack/loadbalancer/v2/loadbalancer.go | 5 +++++ .../loadbalancer/v2/listeners/requests.go | 17 +++++++++++++++ .../loadbalancer/v2/listeners/results.go | 3 +++ .../v2/listeners/testing/fixtures.go | 21 +++++++++++++------ .../v2/listeners/testing/requests_test.go | 3 +++ 5 files changed, 43 insertions(+), 6 deletions(-) diff --git a/acceptance/openstack/loadbalancer/v2/loadbalancer.go b/acceptance/openstack/loadbalancer/v2/loadbalancer.go index 944a2cdb9e..244d8d90b9 100644 --- a/acceptance/openstack/loadbalancer/v2/loadbalancer.go +++ b/acceptance/openstack/loadbalancer/v2/loadbalancer.go @@ -67,6 +67,9 @@ func CreateListenerHTTP(t *testing.T, client *gophercloud.ServiceClient, lb *loa "X-Forwarded-For": "true", } + tlsVersions := []listeners.TLSVersion{"TLSv1.2", "TLSv1.3"} + tlsVersionsExp := []string{"TLSv1.2", "TLSv1.3"} + createOpts := listeners.CreateOpts{ Name: listenerName, Description: listenerDescription, @@ -74,6 +77,7 @@ func CreateListenerHTTP(t *testing.T, client *gophercloud.ServiceClient, lb *loa InsertHeaders: headers, Protocol: listeners.ProtocolHTTP, ProtocolPort: listenerPort, + TLSVersions: tlsVersions, } listener, err := listeners.Create(client, createOpts).Extract() @@ -93,6 +97,7 @@ func CreateListenerHTTP(t *testing.T, client *gophercloud.ServiceClient, lb *loa th.AssertEquals(t, listener.Protocol, string(listeners.ProtocolHTTP)) th.AssertEquals(t, listener.ProtocolPort, listenerPort) th.AssertDeepEquals(t, listener.InsertHeaders, headers) + th.AssertDeepEquals(t, listener.TLSVersions, tlsVersionsExp) return listener, nil } diff --git a/openstack/loadbalancer/v2/listeners/requests.go b/openstack/loadbalancer/v2/listeners/requests.go index 08a1f5823e..c15d65dab0 100644 --- a/openstack/loadbalancer/v2/listeners/requests.go +++ b/openstack/loadbalancer/v2/listeners/requests.go @@ -22,6 +22,17 @@ const ( ProtocolTerminatedHTTPS Protocol = "TERMINATED_HTTPS" ) +// 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 { @@ -153,6 +164,9 @@ type CreateOpts struct { // A list of IPv4, IPv6 or mix of both CIDRs AllowedCIDRs []string `json:"allowed_cidrs,omitempty"` + + // A list of TLS protocol versions. Available from microversion 2.17 + TLSVersions []TLSVersion `json:"tls_versions,omitempty"` } // ToListenerCreateMap builds a request body from CreateOpts. @@ -232,6 +246,9 @@ type UpdateOpts struct { // A list of IPv4, IPv6 or mix of both CIDRs AllowedCIDRs *[]string `json:"allowed_cidrs,omitempty"` + + // A list of TLS protocol versions. Available from microversion 2.17 + TLSVersions *[]TLSVersion `json:"tls_versions,omitempty"` } // ToListenerUpdateMap builds a request body from UpdateOpts. diff --git a/openstack/loadbalancer/v2/listeners/results.go b/openstack/loadbalancer/v2/listeners/results.go index 1d5761fb84..be2a6dcfed 100644 --- a/openstack/loadbalancer/v2/listeners/results.go +++ b/openstack/loadbalancer/v2/listeners/results.go @@ -83,6 +83,9 @@ type Listener struct { // A list of IPv4, IPv6 or mix of both CIDRs AllowedCIDRs []string `json:"allowed_cidrs"` + + // A list of TLS protocol versions. Available from microversion 2.17 + TLSVersions []string `json:"tls_versions"` } type Stats struct { diff --git a/openstack/loadbalancer/v2/listeners/testing/fixtures.go b/openstack/loadbalancer/v2/listeners/testing/fixtures.go index b74f2638b9..3efdf0af31 100644 --- a/openstack/loadbalancer/v2/listeners/testing/fixtures.go +++ b/openstack/loadbalancer/v2/listeners/testing/fixtures.go @@ -29,7 +29,8 @@ const ListenersListBody = ` "allowed_cidrs": [ "192.0.2.0/24", "198.51.100.0/24" - ] + ], + "tls_versions": ["TLSv1.2", "TLSv1.3"] }, { "id": "36e08a3e-a78f-4b40-a229-1e7e23eee1ab", @@ -54,7 +55,8 @@ const ListenersListBody = ` "allowed_cidrs": [ "192.0.2.0/24", "198.51.100.0/24" - ] + ], + "tls_versions": ["TLSv1.2"] } ] } @@ -86,7 +88,8 @@ const SingleListenerBody = ` "allowed_cidrs": [ "192.0.2.0/24", "198.51.100.0/24" - ] + ], + "tls_versions": ["TLSv1.2"] } } ` @@ -114,7 +117,8 @@ const PostUpdateListenerBody = ` "insert_headers": { "X-Forwarded-For": "true", "X-Forwarded-Port": "false" - } + }, + "tls_versions": ["TLSv1.2", "TLSv1.3"] } } ` @@ -146,6 +150,7 @@ var ( DefaultTlsContainerRef: "2c433435-20de-4411-84ae-9cc8917def76", SniContainerRefs: []string{"3d328d82-2547-4921-ac2f-61c3b452b5ff", "b3cfd7e3-8c19-455c-8ebb-d78dfd8f7e7d"}, AllowedCIDRs: []string{"192.0.2.0/24", "198.51.100.0/24"}, + TLSVersions: []string{"TLSv1.2", "TLSv1.3"}, } ListenerDb = listeners.Listener{ ID: "36e08a3e-a78f-4b40-a229-1e7e23eee1ab", @@ -166,6 +171,7 @@ var ( TimeoutTCPInspect: 0, InsertHeaders: map[string]string{"X-Forwarded-For": "true"}, AllowedCIDRs: []string{"192.0.2.0/24", "198.51.100.0/24"}, + TLSVersions: []string{"TLSv1.2"}, } ListenerUpdated = listeners.Listener{ ID: "36e08a3e-a78f-4b40-a229-1e7e23eee1ab", @@ -188,6 +194,7 @@ var ( "X-Forwarded-For": "true", "X-Forwarded-Port": "false", }, + TLSVersions: []string{"TLSv1.2", "TLSv1.3"}, } ListenerStatsTree = listeners.Stats{ ActiveConnections: 0, @@ -239,7 +246,8 @@ func HandleListenerCreationSuccessfully(t *testing.T, response string) { "allowed_cidrs": [ "192.0.2.0/24", "198.51.100.0/24" - ] + ], + "tls_versions": ["TLSv1.2"] } }`) @@ -289,7 +297,8 @@ func HandleListenerUpdateSuccessfully(t *testing.T) { "insert_headers": { "X-Forwarded-For": "true", "X-Forwarded-Port": "false" - } + }, + "tls_versions": ["TLSv1.2", "TLSv1.3"] } }`) diff --git a/openstack/loadbalancer/v2/listeners/testing/requests_test.go b/openstack/loadbalancer/v2/listeners/testing/requests_test.go index 1cdb553ab1..21fc0a4bea 100644 --- a/openstack/loadbalancer/v2/listeners/testing/requests_test.go +++ b/openstack/loadbalancer/v2/listeners/testing/requests_test.go @@ -68,6 +68,7 @@ func TestCreateListener(t *testing.T) { ProtocolPort: 3306, InsertHeaders: map[string]string{"X-Forwarded-For": "true"}, AllowedCIDRs: []string{"192.0.2.0/24", "198.51.100.0/24"}, + TLSVersions: []listeners.TLSVersion{"TLSv1.2"}, }).Extract() th.AssertNoErr(t, err) @@ -134,6 +135,7 @@ func TestUpdateListener(t *testing.T) { "X-Forwarded-For": "true", "X-Forwarded-Port": "false", } + tlsVersions := []listeners.TLSVersion{"TLSv1.2", "TLSv1.3"} actual, err := listeners.Update(client, "4ec89087-d057-4e2c-911f-60a3b47ee304", listeners.UpdateOpts{ Name: &name, ConnLimit: &i1001, @@ -143,6 +145,7 @@ func TestUpdateListener(t *testing.T) { TimeoutMemberConnect: &i181000, TimeoutTCPInspect: &i181000, InsertHeaders: &insertHeaders, + TLSVersions: &tlsVersions, }).Extract() if err != nil { t.Fatalf("Unexpected Update error: %v", err) From 0fc2c97ff6dae0f127c06db76a4cce21f4f5aa60 Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Thu, 29 Apr 2021 11:27:43 -0600 Subject: [PATCH 07/26] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a62c6e2fa..da1dcfda95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ IMPROVEMENTS * Added `orchestration/v1/stacks.ListOpts.ShowHidden` [GH-2104](https://github.com/gophercloud/gophercloud/pull/2104) * Added `loadbalancer/v2/listeners.ProtocolSCTP` [GH-2149](https://github.com/gophercloud/gophercloud/pull/2149) +* Added `loadbalancer/v2/listeners.CreateOpts.TLSVersions` [GH-2150](https://github.com/gophercloud/gophercloud/pull/2150) +* Added `loadbalancer/v2/listeners.UpdateOpts.TLSVersions` [GH-2150](https://github.com/gophercloud/gophercloud/pull/2150) ## 0.17.0 (April 9, 2021) From d49f498c5057ef587521e6aeeb5f3f440264726d Mon Sep 17 00:00:00 2001 From: Zane Bitter Date: Mon, 10 May 2021 23:33:22 -0400 Subject: [PATCH 08/26] baremetal: add network_data to Node interface (#2154) This field was added in microversion 1.66 and appears in the Victoria release. Depends-On: https://github.com/theopenlab/openlab-zuul-jobs/pull/1147 --- openstack/baremetal/v1/nodes/requests.go | 3 +++ openstack/baremetal/v1/nodes/results.go | 3 +++ 2 files changed, 6 insertions(+) diff --git a/openstack/baremetal/v1/nodes/requests.go b/openstack/baremetal/v1/nodes/requests.go index 9648abe5c5..4a04f750b5 100644 --- a/openstack/baremetal/v1/nodes/requests.go +++ b/openstack/baremetal/v1/nodes/requests.go @@ -247,6 +247,9 @@ type CreateOpts struct { // A string or UUID of the tenant who owns the baremetal node. Owner string `json:"owner,omitempty"` + + // Static network configuration to use during deployment and cleaning. + NetworkData map[string]interface{} `json:"network_data,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 70dc9a0447..caadd673aa 100644 --- a/openstack/baremetal/v1/nodes/results.go +++ b/openstack/baremetal/v1/nodes/results.go @@ -192,6 +192,9 @@ type Node struct { // A string or UUID of the tenant who owns the baremetal node. Owner string `json:"owner"` + + // Static network configuration to use during deployment and cleaning. + NetworkData map[string]interface{} `json:"network_data"` } // NodePage abstracts the raw results of making a List() request against From ec3f761dbd2a3bab5efefac50a7bae7bd7063873 Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Mon, 10 May 2021 21:34:49 -0600 Subject: [PATCH 09/26] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index da1dcfda95..51d0aafec7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ IMPROVEMENTS * Added `loadbalancer/v2/listeners.ProtocolSCTP` [GH-2149](https://github.com/gophercloud/gophercloud/pull/2149) * Added `loadbalancer/v2/listeners.CreateOpts.TLSVersions` [GH-2150](https://github.com/gophercloud/gophercloud/pull/2150) * Added `loadbalancer/v2/listeners.UpdateOpts.TLSVersions` [GH-2150](https://github.com/gophercloud/gophercloud/pull/2150) +* Added `baremetal/v1/nodes.CreateOpts.NetworkData` [GH-2154](https://github.com/gophercloud/gophercloud/pull/2154) +* Added `baremetal/v1/nodes.Node.NetworkData` [GH-2154](https://github.com/gophercloud/gophercloud/pull/2154) ## 0.17.0 (April 9, 2021) From 91506b94ba5cdd29198b1dee99fe641b49f8823c Mon Sep 17 00:00:00 2001 From: Ikko Ashimine Date: Thu, 13 May 2021 08:50:03 +0900 Subject: [PATCH 10/26] Networking v2: Fix typo in results.go (#2156) Descripton -> Description --- openstack/networking/v2/extensions/security/rules/results.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openstack/networking/v2/extensions/security/rules/results.go b/openstack/networking/v2/extensions/security/rules/results.go index 3bf5501d92..52ac3f7a75 100644 --- a/openstack/networking/v2/extensions/security/rules/results.go +++ b/openstack/networking/v2/extensions/security/rules/results.go @@ -17,7 +17,7 @@ type SecGroupRule struct { // instance. An egress rule is applied to traffic leaving the instance. Direction string - // Descripton of the rule + // Description of the rule Description string `json:"description"` // Must be IPv4 or IPv6, and addresses represented in CIDR must match the From 12b4c582fb975a3ad5896a461400549277eda12c Mon Sep 17 00:00:00 2001 From: Parasyris Nikolaos Date: Thu, 13 May 2021 01:53:18 +0200 Subject: [PATCH 11/26] Add SCTP and PROXYV2 protocol for octavia pools (#2158) --- openstack/loadbalancer/v2/pools/requests.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/openstack/loadbalancer/v2/pools/requests.go b/openstack/loadbalancer/v2/pools/requests.go index bf93656b02..0379d0385c 100644 --- a/openstack/loadbalancer/v2/pools/requests.go +++ b/openstack/loadbalancer/v2/pools/requests.go @@ -71,6 +71,10 @@ const ( ProtocolPROXY Protocol = "PROXY" ProtocolHTTP Protocol = "HTTP" ProtocolHTTPS Protocol = "HTTPS" + // Protocol PROXYV2 requires octavia microversion 2.22 + ProtocolPROXYV2 Protocol = "PROXYV2" + // Protocol SCTP requires octavia microversion 2.23 + ProtocolSCTP Protocol = "SCTP" ) // CreateOptsBuilder allows extensions to add additional parameters to the @@ -88,7 +92,8 @@ type CreateOpts struct { LBMethod LBMethod `json:"lb_algorithm" required:"true"` // The protocol used by the pool members, you can use either - // ProtocolTCP, ProtocolUDP, ProtocolPROXY, ProtocolHTTP, or ProtocolHTTPS. + // ProtocolTCP, ProtocolUDP, ProtocolPROXY, ProtocolHTTP, ProtocolHTTPS, + // ProtocolSCTP or ProtocolPROXYV2. Protocol Protocol `json:"protocol" required:"true"` // The Loadbalancer on which the members of the pool will be associated with. From 2841b2e97e75d212b8c9002482a6c87f6d937c63 Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Wed, 12 May 2021 17:54:30 -0600 Subject: [PATCH 12/26] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 51d0aafec7..4fe5d774c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ IMPROVEMENTS * Added `loadbalancer/v2/listeners.UpdateOpts.TLSVersions` [GH-2150](https://github.com/gophercloud/gophercloud/pull/2150) * Added `baremetal/v1/nodes.CreateOpts.NetworkData` [GH-2154](https://github.com/gophercloud/gophercloud/pull/2154) * Added `baremetal/v1/nodes.Node.NetworkData` [GH-2154](https://github.com/gophercloud/gophercloud/pull/2154) +* Added `loadbalancer/v2/pools.ProtocolPROXYV2` [GH-2158](https://github.com/gophercloud/gophercloud/pull/2158) +* Added `loadbalancer/v2/pools.ProtocolSCTP` [GH-2158](https://github.com/gophercloud/gophercloud/pull/2158) ## 0.17.0 (April 9, 2021) From cb7437a9f284c9731e784eb14d2546283e333b76 Mon Sep 17 00:00:00 2001 From: Abhinav Anand <6172555+abnvanand@users.noreply.github.com> Date: Tue, 18 May 2021 03:04:38 +0530 Subject: [PATCH 13/26] Add resource provider allocations API for placement (#2162) --- .../placement/v1/resourceproviders_test.go | 30 +++++++++ .../placement/v1/resourceproviders/doc.go | 7 ++ .../v1/resourceproviders/requests.go | 6 ++ .../placement/v1/resourceproviders/results.go | 22 +++++++ .../v1/resourceproviders/testing/fixtures.go | 65 +++++++++++++++++++ .../testing/requests_test.go | 11 ++++ .../placement/v1/resourceproviders/urls.go | 4 ++ 7 files changed, 145 insertions(+) diff --git a/acceptance/openstack/placement/v1/resourceproviders_test.go b/acceptance/openstack/placement/v1/resourceproviders_test.go index 52d2137800..0092b10ef1 100644 --- a/acceptance/openstack/placement/v1/resourceproviders_test.go +++ b/acceptance/openstack/placement/v1/resourceproviders_test.go @@ -142,3 +142,33 @@ func TestResourceProviderTraits(t *testing.T) { tools.PrintResource(t, usage) } + +func TestResourceProviderAllocations(t *testing.T) { + clients.SkipRelease(t, "stable/mitaka") + clients.SkipRelease(t, "stable/newton") + clients.SkipRelease(t, "stable/ocata") + clients.SkipRelease(t, "stable/pike") + clients.SkipRelease(t, "stable/queens") + clients.RequireAdmin(t) + + client, err := clients.NewPlacementV1Client() + th.AssertNoErr(t, err) + + // first create new resource provider + name := tools.RandomString("TESTACC-", 8) + t.Logf("Attempting to create resource provider: %s", name) + + createOpts := resourceproviders.CreateOpts{ + Name: name, + } + + client.Microversion = "1.20" + resourceProvider, err := resourceproviders.Create(client, createOpts).Extract() + th.AssertNoErr(t, err) + + // now get the allocations for the newly created resource provider + usage, err := resourceproviders.GetAllocations(client, resourceProvider.UUID).Extract() + th.AssertNoErr(t, err) + + tools.PrintResource(t, usage) +} diff --git a/openstack/placement/v1/resourceproviders/doc.go b/openstack/placement/v1/resourceproviders/doc.go index 051d404dbd..1945958438 100644 --- a/openstack/placement/v1/resourceproviders/doc.go +++ b/openstack/placement/v1/resourceproviders/doc.go @@ -50,5 +50,12 @@ Example to get resource providers traits panic(err) } +Example to get resource providers allocations + + rp, err := resourceproviders.GetAllocations(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 f0da23f989..c2c9980838 100644 --- a/openstack/placement/v1/resourceproviders/requests.go +++ b/openstack/placement/v1/resourceproviders/requests.go @@ -108,6 +108,12 @@ func GetInventories(client *gophercloud.ServiceClient, resourceProviderID string return } +func GetAllocations(client *gophercloud.ServiceClient, resourceProviderID string) (r GetAllocationsResult) { + resp, err := client.Get(getResourceProviderAllocationsURL(client, resourceProviderID), &r.Body, nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + func GetTraits(client *gophercloud.ServiceClient, resourceProviderID string) (r GetTraitsResult) { resp, err := client.Get(getResourceProviderTraitsURL(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 0562451777..582cb86af7 100644 --- a/openstack/placement/v1/resourceproviders/results.go +++ b/openstack/placement/v1/resourceproviders/results.go @@ -47,11 +47,20 @@ type Inventory struct { Total int `json:"total"` } +type Allocation struct { + Resources map[string]int `json:"resources"` +} + type ResourceProviderInventories struct { ResourceProviderGeneration int `json:"resource_provider_generation"` Inventories map[string]Inventory `json:"inventories"` } +type ResourceProviderAllocations struct { + ResourceProviderGeneration int `json:"resource_provider_generation"` + Allocations map[string]Allocation `json:"allocations"` +} + type ResourceProviderTraits struct { ResourceProviderGeneration int `json:"resource_provider_generation"` Traits []string `json:"traits"` @@ -122,6 +131,19 @@ func (r GetInventoriesResult) Extract() (*ResourceProviderInventories, error) { 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 { + gophercloud.Result +} + +// Extract interprets a GetAllocationsResult as a ResourceProviderAllocations. +func (r GetAllocationsResult) Extract() (*ResourceProviderAllocations, error) { + var s ResourceProviderAllocations + err := r.ExtractInto(&s) + return &s, err +} + // GetTraitsResult is the response of a Get traits operations. Call its Extract method // to interpret it as a ResourceProviderTraits. type GetTraitsResult struct { diff --git a/openstack/placement/v1/resourceproviders/testing/fixtures.go b/openstack/placement/v1/resourceproviders/testing/fixtures.go index 70d31ec145..29bf4c68fe 100644 --- a/openstack/placement/v1/resourceproviders/testing/fixtures.go +++ b/openstack/placement/v1/resourceproviders/testing/fixtures.go @@ -105,6 +105,32 @@ const InventoriesBody = ` } ` +const AllocationsBody = ` +{ + "allocations": { + "56785a3f-6f1c-4fec-af0b-0faf075b1fcb": { + "resources": { + "MEMORY_MB": 256, + "VCPU": 1 + } + }, + "9afd5aeb-d6b9-4dea-a588-1e6327a91834": { + "resources": { + "MEMORY_MB": 512, + "VCPU": 2 + } + }, + "9d16a611-e7f9-4ef3-be26-c61ed01ecefb": { + "resources": { + "MEMORY_MB": 1024, + "VCPU": 1 + } + } + }, + "resource_provider_generation": 12 +} +` + const TraitsBody = ` { "resource_provider_generation": 1, @@ -187,6 +213,30 @@ var ExpectedInventories = resourceproviders.ResourceProviderInventories{ }, } +var ExpectedAllocations = resourceproviders.ResourceProviderAllocations{ + ResourceProviderGeneration: 12, + Allocations: map[string]resourceproviders.Allocation{ + "56785a3f-6f1c-4fec-af0b-0faf075b1fcb": { + Resources: map[string]int{ + "MEMORY_MB": 256, + "VCPU": 1, + }, + }, + "9afd5aeb-d6b9-4dea-a588-1e6327a91834": { + Resources: map[string]int{ + "MEMORY_MB": 512, + "VCPU": 2, + }, + }, + "9d16a611-e7f9-4ef3-be26-c61ed01ecefb": { + Resources: map[string]int{ + "MEMORY_MB": 1024, + "VCPU": 1, + }, + }, + }, +} + var ExpectedTraits = resourceproviders.ResourceProviderTraits{ ResourceProviderGeneration: 1, Traits: []string{ @@ -250,6 +300,21 @@ func HandleResourceProviderGetInventories(t *testing.T) { }) } +func HandleResourceProviderGetAllocations(t *testing.T) { + allocationsTestUrl := fmt.Sprintf("/resource_providers/%s/allocations", ResourceProviderTestID) + + th.Mux.HandleFunc(allocationsTestUrl, + 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.Fprintf(w, AllocationsBody) + }) +} + func HandleResourceProviderGetTraits(t *testing.T) { traitsTestUrl := fmt.Sprintf("/resource_providers/%s/traits", ResourceProviderTestID) diff --git a/openstack/placement/v1/resourceproviders/testing/requests_test.go b/openstack/placement/v1/resourceproviders/testing/requests_test.go index bf3837b8b0..896df74812 100644 --- a/openstack/placement/v1/resourceproviders/testing/requests_test.go +++ b/openstack/placement/v1/resourceproviders/testing/requests_test.go @@ -78,6 +78,17 @@ func TestGetResourceProvidersInventories(t *testing.T) { th.AssertDeepEquals(t, ExpectedInventories, *actual) } +func TestGetResourceProvidersAllocations(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + + HandleResourceProviderGetAllocations(t) + + actual, err := resourceproviders.GetAllocations(fake.ServiceClient(), ResourceProviderTestID).Extract() + th.AssertNoErr(t, err) + th.AssertDeepEquals(t, ExpectedAllocations, *actual) +} + func TestGetResourceProvidersTraits(t *testing.T) { th.SetupHTTP() defer th.TeardownHTTP() diff --git a/openstack/placement/v1/resourceproviders/urls.go b/openstack/placement/v1/resourceproviders/urls.go index 5f0ef2e347..6cc2a57c96 100644 --- a/openstack/placement/v1/resourceproviders/urls.go +++ b/openstack/placement/v1/resourceproviders/urls.go @@ -18,6 +18,10 @@ func getResourceProviderInventoriesURL(client *gophercloud.ServiceClient, resour return client.ServiceURL(apiName, resourceProviderID, "inventories") } +func getResourceProviderAllocationsURL(client *gophercloud.ServiceClient, resourceProviderID string) string { + return client.ServiceURL(apiName, resourceProviderID, "allocations") +} + func getResourceProviderTraitsURL(client *gophercloud.ServiceClient, resourceProviderID string) string { return client.ServiceURL(apiName, resourceProviderID, "traits") } From 0be823b69be8891e4571548f528284c6995386e2 Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Mon, 17 May 2021 15:35:36 -0600 Subject: [PATCH 14/26] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fe5d774c2..c656651ee7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ IMPROVEMENTS * Added `baremetal/v1/nodes.Node.NetworkData` [GH-2154](https://github.com/gophercloud/gophercloud/pull/2154) * Added `loadbalancer/v2/pools.ProtocolPROXYV2` [GH-2158](https://github.com/gophercloud/gophercloud/pull/2158) * Added `loadbalancer/v2/pools.ProtocolSCTP` [GH-2158](https://github.com/gophercloud/gophercloud/pull/2158) +* Added `placement/v1/resourceproviders.GetAllocations` [GH-2162](https://github.com/gophercloud/gophercloud/pull/2162) ## 0.17.0 (April 9, 2021) From 965c5608e42226c8348eae18a9de019a7fc1d2a1 Mon Sep 17 00:00:00 2001 From: Bob Fournier Date: Thu, 20 May 2021 21:36:50 -0400 Subject: [PATCH 15/26] Add missing bios interface fields to Ironic API (#2164) The bios interface fields are in the Ironic API but were missing from the Ironic API documentation and not included in gophercloud. This change adds in the bios interface to the node create, node list, and node driver validation APIs. For reference, these are the Ironic updates to the api-ref documentation: https://review.opendev.org/c/openstack/ironic/+/757353 https://review.opendev.org/c/openstack/ironic/+/791493 https://review.opendev.org/c/openstack/ironic/+/792210 --- openstack/baremetal/v1/nodes/requests.go | 3 +++ openstack/baremetal/v1/nodes/results.go | 4 ++++ openstack/baremetal/v1/nodes/testing/fixtures.go | 7 +++++++ 3 files changed, 14 insertions(+) diff --git a/openstack/baremetal/v1/nodes/requests.go b/openstack/baremetal/v1/nodes/requests.go index 4a04f750b5..a25c0ea2c3 100644 --- a/openstack/baremetal/v1/nodes/requests.go +++ b/openstack/baremetal/v1/nodes/requests.go @@ -185,6 +185,9 @@ type CreateOpts struct { // Requires microversion 1.47 or later. AutomatedClean *bool `json:"automated_clean,omitempty"` + // The BIOS interface for a Node, e.g. “redfish”. + BIOSInterface string `json:"bios_interface,omitempty"` + // The boot interface for a Node, e.g. “pxe”. BootInterface string `json:"boot_interface,omitempty"` diff --git a/openstack/baremetal/v1/nodes/results.go b/openstack/baremetal/v1/nodes/results.go index caadd673aa..22bc598f3a 100644 --- a/openstack/baremetal/v1/nodes/results.go +++ b/openstack/baremetal/v1/nodes/results.go @@ -145,6 +145,9 @@ type Node struct { // For more details, see: https://docs.openstack.org/ironic/latest/install/configure-nova-flavors.html ResourceClass string `json:"resource_class"` + // BIOS interface for a Node, e.g. “redfish”. + BIOSInterface string `json:"bios_interface"` + // Boot interface for a Node, e.g. “pxe”. BootInterface string `json:"boot_interface"` @@ -301,6 +304,7 @@ type DriverValidation struct { // Ironic validates whether the Node’s driver has enough information to manage the Node. This polls each interface on // the driver, and returns the status of that interface as an DriverValidation struct. type NodeValidation struct { + BIOS DriverValidation `json:"bios"` Boot DriverValidation `json:"boot"` Console DriverValidation `json:"console"` Deploy DriverValidation `json:"deploy"` diff --git a/openstack/baremetal/v1/nodes/testing/fixtures.go b/openstack/baremetal/v1/nodes/testing/fixtures.go index a849d05ee1..18f3588ce7 100644 --- a/openstack/baremetal/v1/nodes/testing/fixtures.go +++ b/openstack/baremetal/v1/nodes/testing/fixtures.go @@ -638,6 +638,7 @@ var ( CleanStep: map[string]interface{}{}, DeployStep: map[string]interface{}{}, ResourceClass: "", + BIOSInterface: "no-bios", BootInterface: "pxe", ConsoleInterface: "no-console", DeployInterface: "iscsi", @@ -656,6 +657,10 @@ var ( } NodeFooValidation = nodes.NodeValidation{ + BIOS: nodes.DriverValidation{ + Result: false, + Reason: "Driver ipmi does not support bios (disabled or not implemented).", + }, Boot: nodes.DriverValidation{ Result: false, Reason: "Cannot validate image information for node a62b8495-52e2-407b-b3cb-62775d04c2b8 because one or more parameters are missing from its instance_info and insufficent information is present to boot from a remote volume. Missing are: ['ramdisk', 'kernel', 'image_source']", @@ -730,6 +735,7 @@ var ( CleanStep: map[string]interface{}{}, DeployStep: map[string]interface{}{}, ResourceClass: "", + BIOSInterface: "no-bios", BootInterface: "pxe", ConsoleInterface: "no-console", DeployInterface: "iscsi", @@ -773,6 +779,7 @@ var ( CleanStep: map[string]interface{}{}, DeployStep: map[string]interface{}{}, ResourceClass: "", + BIOSInterface: "no-bios", BootInterface: "pxe", ConsoleInterface: "no-console", DeployInterface: "iscsi", From e94bc6d0e997f14bb9152e51046668a61bfa9830 Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Thu, 20 May 2021 19:38:54 -0600 Subject: [PATCH 16/26] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c656651ee7..aadbb77d7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,9 @@ IMPROVEMENTS * Added `loadbalancer/v2/pools.ProtocolPROXYV2` [GH-2158](https://github.com/gophercloud/gophercloud/pull/2158) * Added `loadbalancer/v2/pools.ProtocolSCTP` [GH-2158](https://github.com/gophercloud/gophercloud/pull/2158) * Added `placement/v1/resourceproviders.GetAllocations` [GH-2162](https://github.com/gophercloud/gophercloud/pull/2162) +* Added `baremetal/v1/nodes.CreateOpts.BIOSInterface` [GH-2164](https://github.com/gophercloud/gophercloud/pull/2164) +* Added `baremetal/v1/nodes.Node.BIOSInterface` [GH-2164](https://github.com/gophercloud/gophercloud/pull/2164) +* Added `baremetal/v1/nodes.NodeValidation.BIOS` [GH-2164](https://github.com/gophercloud/gophercloud/pull/2164) ## 0.17.0 (April 9, 2021) From c0932594cee4a474889dbf062cf8f60bcc64f3d5 Mon Sep 17 00:00:00 2001 From: Bob Fournier Date: Wed, 26 May 2021 02:07:54 -0400 Subject: [PATCH 17/26] Add support for baremetal bios endpoint (#2171) For #2165. The baremetal bios endpoint has been available in the Ironic API since version 1.40 and is documented in the API reference here - https://docs.openstack.org/api-ref/baremetal/?expanded=#node-bios-nodes. It provides a list of all bios settings by node or a particular setting on a node. The ironic API code is here: https://github.com/openstack/ironic/blob/master/ironic/api/controllers/v1/bios.py#L57 --- openstack/baremetal/v1/nodes/requests.go | 18 +++++ openstack/baremetal/v1/nodes/results.go | 45 ++++++++++++- .../baremetal/v1/nodes/testing/fixtures.go | 67 +++++++++++++++++++ .../v1/nodes/testing/requests_test.go | 22 ++++++ openstack/baremetal/v1/nodes/urls.go | 8 +++ 5 files changed, 159 insertions(+), 1 deletion(-) diff --git a/openstack/baremetal/v1/nodes/requests.go b/openstack/baremetal/v1/nodes/requests.go index a25c0ea2c3..33a649cd9b 100644 --- a/openstack/baremetal/v1/nodes/requests.go +++ b/openstack/baremetal/v1/nodes/requests.go @@ -639,3 +639,21 @@ func SetRAIDConfig(client *gophercloud.ServiceClient, id string, raidConfigOptsB _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return } + +// Get the current BIOS Settings for the given Node. +func ListBIOSSettings(client *gophercloud.ServiceClient, id string) (r ListBIOSSettingsResult) { + resp, err := client.Get(biosListSettingsURL(client, id), &r.Body, &gophercloud.RequestOpts{ + OkCodes: []int{200}, + }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + +// Get one BIOS Setting for the given Node. +func GetBIOSSetting(client *gophercloud.ServiceClient, id string, setting string) (r GetBIOSSettingResult) { + resp, err := client.Get(biosGetSettingURL(client, id, setting), &r.Body, &gophercloud.RequestOpts{ + OkCodes: []int{200}, + }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} diff --git a/openstack/baremetal/v1/nodes/results.go b/openstack/baremetal/v1/nodes/results.go index 22bc598f3a..6566b141a0 100644 --- a/openstack/baremetal/v1/nodes/results.go +++ b/openstack/baremetal/v1/nodes/results.go @@ -48,6 +48,23 @@ func ExtractNodesInto(r pagination.Page, v interface{}) error { return r.(NodePage).Result.ExtractIntoSlicePtr(v, "nodes") } +// Extract interprets a BIOSSettingsResult as an array of BIOSSetting structs, if possible. +func (r ListBIOSSettingsResult) Extract() ([]BIOSSetting, error) { + var s struct { + Settings []BIOSSetting `json:"bios"` + } + + err := r.ExtractInto(&s) + return s.Settings, err +} + +// Extract interprets a SingleBIOSSettingResult as a BIOSSetting struct, if possible. +func (r GetBIOSSettingResult) Extract() (*BIOSSetting, error) { + var s SingleBIOSSetting + err := r.ExtractInto(&s) + return &s.Setting, err +} + // Node represents a node in the OpenStack Bare Metal API. type Node struct { // Whether automated cleaning is enabled or disabled on this node. @@ -276,7 +293,7 @@ type BootDeviceResult struct { gophercloud.Result } -// BootDeviceResult is the response from a GetBootDevice operation. Call its Extract +// SetBootDeviceResult is the response from a SetBootDevice operation. Call its Extract // method to interpret it as a BootDeviceOpts struct. type SetBootDeviceResult struct { gophercloud.ErrResult @@ -294,6 +311,18 @@ type ChangePowerStateResult struct { gophercloud.ErrResult } +// ListBIOSSettingsResult is the response from a ListBIOSSettings operation. Call its Extract +// method to interpret it as an array of BIOSSetting structs. +type ListBIOSSettingsResult struct { + gophercloud.Result +} + +// GetBIOSSettingResult is the response from a GetBIOSSetting operation. Call its Extract +// method to interpret it as a BIOSSetting struct. +type GetBIOSSettingResult struct { + gophercloud.Result +} + // Each element in the response will contain a “result” variable, which will have a value of “true” or “false”, and // also potentially a reason. A value of nil indicates that the Node’s driver does not support that interface. type DriverValidation struct { @@ -317,6 +346,20 @@ type NodeValidation struct { Storage DriverValidation `json:"storage"` } +// A particular BIOS setting for a node in the OpenStack Bare Metal API. +type BIOSSetting struct { + + // Identifier for the BIOS setting. + Name string `json:"name"` + + // Value of the BIOS setting. + Value string `json:"value"` +} + +type SingleBIOSSetting struct { + Setting BIOSSetting +} + // ChangeStateResult is the response from any state change operation. Call its ExtractErr // method to determine if the call succeeded or failed. type ChangeStateResult struct { diff --git a/openstack/baremetal/v1/nodes/testing/fixtures.go b/openstack/baremetal/v1/nodes/testing/fixtures.go index 18f3588ce7..157d338b61 100644 --- a/openstack/baremetal/v1/nodes/testing/fixtures.go +++ b/openstack/baremetal/v1/nodes/testing/fixtures.go @@ -604,6 +604,33 @@ const NodeProvisionStateConfigDriveBody = ` } ` +const NodeBIOSSettingsBody = ` +{ + "bios": [ + { + "name": "Proc1L2Cache", + "value": "10x256 KB" + }, + { + "name": "Proc1NumCores", + "value": "10" + }, + { + "name": "ProcVirtualization", + "value": "Enabled" + } + ] +} +` +const NodeSingleBIOSSettingBody = ` +{ + "Setting": { + "name": "ProcVirtualization", + "value": "Enabled" + } +} +` + var ( NodeFoo = nodes.Node{ UUID: "d2630783-6ec8-4836-b556-ab427c4b581e", @@ -811,6 +838,26 @@ var ( }, }, } + + NodeBIOSSettings = []nodes.BIOSSetting{ + { + Name: "Proc1L2Cache", + Value: "10x256 KB", + }, + { + Name: "Proc1NumCores", + Value: "10", + }, + { + Name: "ProcVirtualization", + Value: "Enabled", + }, + } + + NodeSingleBIOSSetting = nodes.BIOSSetting{ + Name: "ProcVirtualization", + Value: "Enabled", + } ) // HandleNodeListSuccessfully sets up the test server to respond to a server List request. @@ -1068,3 +1115,23 @@ func HandleSetRAIDConfigMaxSize(t *testing.T) { w.WriteHeader(http.StatusNoContent) }) } + +func HandleListBIOSSettingsSuccessfully(t *testing.T) { + th.Mux.HandleFunc("/nodes/1234asdf/bios", 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.Fprintf(w, NodeBIOSSettingsBody) + }) +} + +func HandleGetBIOSSettingSuccessfully(t *testing.T) { + th.Mux.HandleFunc("/nodes/1234asdf/bios/ProcVirtualization", 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.Fprintf(w, NodeSingleBIOSSettingBody) + }) +} diff --git a/openstack/baremetal/v1/nodes/testing/requests_test.go b/openstack/baremetal/v1/nodes/testing/requests_test.go index 33f5817284..a912d32660 100644 --- a/openstack/baremetal/v1/nodes/testing/requests_test.go +++ b/openstack/baremetal/v1/nodes/testing/requests_test.go @@ -545,3 +545,25 @@ func TestToRAIDConfigMap(t *testing.T) { }) } } + +func TestListBIOSSettings(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + HandleListBIOSSettingsSuccessfully(t) + + c := client.ServiceClient() + actual, err := nodes.ListBIOSSettings(c, "1234asdf").Extract() + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, NodeBIOSSettings, actual) +} + +func TestGetBIOSSetting(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + HandleGetBIOSSettingSuccessfully(t) + + c := client.ServiceClient() + actual, err := nodes.GetBIOSSetting(c, "1234asdf", "ProcVirtualization").Extract() + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, NodeSingleBIOSSetting, *actual) +} diff --git a/openstack/baremetal/v1/nodes/urls.go b/openstack/baremetal/v1/nodes/urls.go index c7ef550365..44ce58f336 100644 --- a/openstack/baremetal/v1/nodes/urls.go +++ b/openstack/baremetal/v1/nodes/urls.go @@ -57,3 +57,11 @@ func provisionStateURL(client *gophercloud.ServiceClient, id string) string { func raidConfigURL(client *gophercloud.ServiceClient, id string) string { return statesResourceURL(client, id, "raid") } + +func biosListSettingsURL(client *gophercloud.ServiceClient, id string) string { + return client.ServiceURL("nodes", id, "bios") +} + +func biosGetSettingURL(client *gophercloud.ServiceClient, id string, setting string) string { + return client.ServiceURL("nodes", id, "bios", setting) +} From 34fae6ed30801505fc2f4157ecbafb733a91b4ba Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Wed, 26 May 2021 00:08:48 -0600 Subject: [PATCH 18/26] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index aadbb77d7a..357c0dd5e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ IMPROVEMENTS * Added `baremetal/v1/nodes.CreateOpts.BIOSInterface` [GH-2164](https://github.com/gophercloud/gophercloud/pull/2164) * Added `baremetal/v1/nodes.Node.BIOSInterface` [GH-2164](https://github.com/gophercloud/gophercloud/pull/2164) * Added `baremetal/v1/nodes.NodeValidation.BIOS` [GH-2164](https://github.com/gophercloud/gophercloud/pull/2164) +* Added `baremetal/v1/nodes.ListBIOSSettings` [GH-2171](https://github.com/gophercloud/gophercloud/pull/2171) +* Added `baremetal/v1/nodes.GetBIOSSetting` [GH-2171](https://github.com/gophercloud/gophercloud/pull/2171) ## 0.17.0 (April 9, 2021) From 351ac5eeffc833f48205f436cac8f0864600ffe8 Mon Sep 17 00:00:00 2001 From: Benjamin Ziehms Date: Tue, 1 Jun 2021 17:10:07 +0200 Subject: [PATCH 19/26] Fix ErrUnexpectedResponseCode expected OK codes (#2173) When receiving a response from OpenStack HTTP response code is checked against a list of OK codes. This list is either specific to the call being made or generic according to the HTTP verb. In the latter scenario, when a wrong code is received, an error is returned that does not contains the actual list of expected OK codes. It is misleading because you may think the list of accepted codes is not correctly defined. Actual: 'Expected HTTP response code [] when accessing [DELETE http://127.0.0.1:35195], but got 200 instead OK' Expected: 'Expected HTTP response code [202 204] when accessing [DELETE http://127.0.0.1:35195], but got 200 instead OK' --- provider_client.go | 2 +- testing/provider_client_test.go | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/provider_client.go b/provider_client.go index f56c1375fe..7797af61c5 100644 --- a/provider_client.go +++ b/provider_client.go @@ -440,7 +440,7 @@ func (client *ProviderClient) doRequest(method, url string, options *RequestOpts respErr := ErrUnexpectedResponseCode{ URL: url, Method: method, - Expected: options.OkCodes, + Expected: okc, Actual: resp.StatusCode, Body: body, ResponseHeader: resp.Header, diff --git a/testing/provider_client_test.go b/testing/provider_client_test.go index a10f8348f3..f7278b024d 100644 --- a/testing/provider_client_test.go +++ b/testing/provider_client_test.go @@ -631,3 +631,23 @@ func TestRequestRetryContext(t *testing.T) { t.Logf("retryCounter: %d, p.MaxBackoffRetries: %d", retryCounter, p.MaxBackoffRetries-1) th.AssertEquals(t, retryCounter, p.MaxBackoffRetries-1) } + +func TestRequestWrongOkCode(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, "OK") + // Returns 200 OK + })) + defer ts.Close() + + p := &gophercloud.ProviderClient{} + + _, err := p.Request("DELETE", ts.URL, &gophercloud.RequestOpts{}) + th.AssertErr(t, err) + if urErr, ok := err.(gophercloud.ErrUnexpectedResponseCode); ok { + // DELETE expects a 202 or 204 by default + // Make sure returned error contains the expected OK codes + th.AssertDeepEquals(t, []int{202, 204}, urErr.Expected) + } else { + t.Fatalf("expected error type gophercloud.ErrUnexpectedResponseCode but got %T", err) + } +} From 054cd0b5598a33fdfb5e37fa09e23cadc2390527 Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Tue, 1 Jun 2021 09:11:21 -0600 Subject: [PATCH 20/26] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 357c0dd5e8..906ca7dca9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## 0.18.0 (Unreleased) +BUG FIXES + +* Fixed expected OK codes to use default codes [GH-2173](https://github.com/gophercloud/gophercloud/pull/2173) + IMPROVEMENTS * Added `orchestration/v1/stacks.ListOpts.ShowHidden` [GH-2104](https://github.com/gophercloud/gophercloud/pull/2104) From 9abac83404d86f64e4a8e887afbc5e9c8a315945 Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Mon, 7 Jun 2021 08:25:51 -0600 Subject: [PATCH 21/26] Acc Tests: Moving to Ubuntu Focal (#2169) * Acc Tests: Moving to Ubuntu Focal * Acc Tests: Disabling Block Storage v2 * Acc Tests: Disabling broken OpenLab test * Acc Tests: More Block Storage v2 to v3 changes * Acc Tests: don't install tempest for ironic * Acc Tests: Disabling TestVolumeActionsUploadImageDestroy as it is failing in OpenLab --- .zuul.yaml | 4 ++-- .../gophercloud-acceptance-test-ironic/run.yaml | 2 +- .../openstack/blockstorage/apiversions_test.go | 4 ++-- .../blockstorage/extensions/schedulerstats_test.go | 2 +- .../blockstorage/extensions/volumeactions_test.go | 14 ++++++++------ .../blockstorage/v3/volumeattachments_test.go | 2 ++ .../openstack/compute/v2/bootfromvolume_test.go | 4 ++-- .../openstack/compute/v2/volumeattach_test.go | 2 +- script/acceptancetest | 2 +- 9 files changed, 20 insertions(+), 16 deletions(-) diff --git a/.zuul.yaml b/.zuul.yaml index 5da8982915..8cba23cb0b 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -13,7 +13,7 @@ Run gophercloud acceptance test on master branch run: .zuul/playbooks/gophercloud-acceptance-test/run.yaml timeout: 18000 # 5 hours - nodeset: ubuntu-bionic + nodeset: ubuntu-focal - job: name: gophercloud-acceptance-test-ironic @@ -21,7 +21,7 @@ description: | Run gophercloud ironic acceptance test on master branch run: .zuul/playbooks/gophercloud-acceptance-test-ironic/run.yaml - nodeset: ubuntu-bionic + nodeset: ubuntu-focal - job: name: gophercloud-acceptance-test-ussuri diff --git a/.zuul/playbooks/gophercloud-acceptance-test-ironic/run.yaml b/.zuul/playbooks/gophercloud-acceptance-test-ironic/run.yaml index b6fcfc32c6..901c29fc95 100644 --- a/.zuul/playbooks/gophercloud-acceptance-test-ironic/run.yaml +++ b/.zuul/playbooks/gophercloud-acceptance-test-ironic/run.yaml @@ -9,7 +9,7 @@ - 'ironic' - role: install-devstack environment: - OVERRIDE_ENABLED_SERVICES: 'g-api,g-reg,q-agt,q-dhcp,q-l3,q-svc,key,mysql,rabbit,ir-api,ir-cond,s-account,s-container,s-object,s-proxy,tempest' + OVERRIDE_ENABLED_SERVICES: 'g-api,g-reg,q-agt,q-dhcp,q-l3,q-svc,key,mysql,rabbit,ir-api,ir-cond,s-account,s-container,s-object,s-proxy' PROJECTS: 'openstack/ironic-python-agent-builder openstack/ironic' tasks: - name: Run ironic acceptance tests with gophercloud diff --git a/acceptance/openstack/blockstorage/apiversions_test.go b/acceptance/openstack/blockstorage/apiversions_test.go index 1adf5c3e8b..5c94d55928 100644 --- a/acceptance/openstack/blockstorage/apiversions_test.go +++ b/acceptance/openstack/blockstorage/apiversions_test.go @@ -11,7 +11,7 @@ import ( ) func TestAPIVersionsList(t *testing.T) { - client, err := clients.NewBlockStorageV2Client() + client, err := clients.NewBlockStorageV3Client() if err != nil { t.Fatalf("Unable to create a blockstorage client: %v", err) } @@ -32,7 +32,7 @@ func TestAPIVersionsList(t *testing.T) { } func TestAPIVersionsGet(t *testing.T) { - client, err := clients.NewBlockStorageV2Client() + client, err := clients.NewBlockStorageV3Client() if err != nil { t.Fatalf("Unable to create a blockstorage client: %v", err) } diff --git a/acceptance/openstack/blockstorage/extensions/schedulerstats_test.go b/acceptance/openstack/blockstorage/extensions/schedulerstats_test.go index b13cb0ec6b..5b4c35e2d3 100644 --- a/acceptance/openstack/blockstorage/extensions/schedulerstats_test.go +++ b/acceptance/openstack/blockstorage/extensions/schedulerstats_test.go @@ -18,7 +18,7 @@ func TestSchedulerStatsList(t *testing.T) { clients.SkipRelease(t, "stable/ocata") clients.SkipRelease(t, "stable/pike") - blockClient, err := clients.NewBlockStorageV2Client() + blockClient, err := clients.NewBlockStorageV3Client() th.AssertNoErr(t, err) listOpts := schedulerstats.ListOpts{ diff --git a/acceptance/openstack/blockstorage/extensions/volumeactions_test.go b/acceptance/openstack/blockstorage/extensions/volumeactions_test.go index 9844410f2f..e5cc069ebc 100644 --- a/acceptance/openstack/blockstorage/extensions/volumeactions_test.go +++ b/acceptance/openstack/blockstorage/extensions/volumeactions_test.go @@ -15,7 +15,9 @@ import ( ) func TestVolumeActionsUploadImageDestroy(t *testing.T) { - blockClient, err := clients.NewBlockStorageV2Client() + t.Skip("Currently failing in OpenLab") + + blockClient, err := clients.NewBlockStorageV3Client() th.AssertNoErr(t, err) computeClient, err := clients.NewComputeV2Client() @@ -35,7 +37,7 @@ func TestVolumeActionsUploadImageDestroy(t *testing.T) { } func TestVolumeActionsAttachCreateDestroy(t *testing.T) { - blockClient, err := clients.NewBlockStorageV2Client() + blockClient, err := clients.NewBlockStorageV3Client() th.AssertNoErr(t, err) computeClient, err := clients.NewComputeV2Client() @@ -59,7 +61,7 @@ func TestVolumeActionsAttachCreateDestroy(t *testing.T) { } func TestVolumeActionsReserveUnreserve(t *testing.T) { - client, err := clients.NewBlockStorageV2Client() + client, err := clients.NewBlockStorageV3Client() th.AssertNoErr(t, err) volume, err := blockstorage.CreateVolume(t, client) @@ -72,7 +74,7 @@ func TestVolumeActionsReserveUnreserve(t *testing.T) { } func TestVolumeActionsExtendSize(t *testing.T) { - blockClient, err := clients.NewBlockStorageV2Client() + blockClient, err := clients.NewBlockStorageV3Client() th.AssertNoErr(t, err) volume, err := blockstorage.CreateVolume(t, blockClient) @@ -91,7 +93,7 @@ func TestVolumeActionsExtendSize(t *testing.T) { } func TestVolumeActionsImageMetadata(t *testing.T) { - blockClient, err := clients.NewBlockStorageV2Client() + blockClient, err := clients.NewBlockStorageV3Client() th.AssertNoErr(t, err) volume, err := blockstorage.CreateVolume(t, blockClient) @@ -103,7 +105,7 @@ func TestVolumeActionsImageMetadata(t *testing.T) { } func TestVolumeActionsSetBootable(t *testing.T) { - blockClient, err := clients.NewBlockStorageV2Client() + blockClient, err := clients.NewBlockStorageV3Client() th.AssertNoErr(t, err) volume, err := blockstorage.CreateVolume(t, blockClient) diff --git a/acceptance/openstack/blockstorage/v3/volumeattachments_test.go b/acceptance/openstack/blockstorage/v3/volumeattachments_test.go index 0ec40ca09c..26921a0525 100644 --- a/acceptance/openstack/blockstorage/v3/volumeattachments_test.go +++ b/acceptance/openstack/blockstorage/v3/volumeattachments_test.go @@ -12,6 +12,8 @@ import ( ) func TestVolumeAttachments(t *testing.T) { + t.Skip("Currently failing in OpenLab") + clients.SkipRelease(t, "stable/mitaka") clients.SkipRelease(t, "stable/newton") clients.SkipRelease(t, "stable/ocata") diff --git a/acceptance/openstack/compute/v2/bootfromvolume_test.go b/acceptance/openstack/compute/v2/bootfromvolume_test.go index 9128747810..f98c561425 100644 --- a/acceptance/openstack/compute/v2/bootfromvolume_test.go +++ b/acceptance/openstack/compute/v2/bootfromvolume_test.go @@ -88,7 +88,7 @@ func TestBootFromExistingVolume(t *testing.T) { computeClient, err := clients.NewComputeV2Client() th.AssertNoErr(t, err) - blockStorageClient, err := clients.NewBlockStorageV2Client() + blockStorageClient, err := clients.NewBlockStorageV3Client() th.AssertNoErr(t, err) volume, err := blockstorage.CreateVolumeFromImage(t, blockStorageClient) @@ -221,7 +221,7 @@ func TestAttachExistingVolume(t *testing.T) { computeClient, err := clients.NewComputeV2Client() th.AssertNoErr(t, err) - blockStorageClient, err := clients.NewBlockStorageV2Client() + blockStorageClient, err := clients.NewBlockStorageV3Client() th.AssertNoErr(t, err) choices, err := clients.AcceptanceTestChoicesFromEnv() diff --git a/acceptance/openstack/compute/v2/volumeattach_test.go b/acceptance/openstack/compute/v2/volumeattach_test.go index 022df830ca..e8d15786d1 100644 --- a/acceptance/openstack/compute/v2/volumeattach_test.go +++ b/acceptance/openstack/compute/v2/volumeattach_test.go @@ -17,7 +17,7 @@ func TestVolumeAttachAttachment(t *testing.T) { client, err := clients.NewComputeV2Client() th.AssertNoErr(t, err) - blockClient, err := clients.NewBlockStorageV2Client() + blockClient, err := clients.NewBlockStorageV3Client() th.AssertNoErr(t, err) server, err := CreateServer(t, client) diff --git a/script/acceptancetest b/script/acceptancetest index 766fc61a9d..6ad683bef3 100755 --- a/script/acceptancetest +++ b/script/acceptancetest @@ -28,8 +28,8 @@ acceptance/openstack/blockstorage/extensions # snapshots_test.go:21: Unable to retrieve snapshots: Resource not found # acceptance/openstack/blockstorage/v1 +# acceptance/openstack/blockstorage/v2 -acceptance/openstack/blockstorage/v2 acceptance/openstack/blockstorage/v3 # No suitable endpoint could be found in the service catalog. From b7d5b2cdd7ffc13e79d924f61571b0e5f74ec91c Mon Sep 17 00:00:00 2001 From: Doug Goldstein Date: Tue, 8 Jun 2021 13:31:01 -0500 Subject: [PATCH 22/26] objects: partially revert e54703519 (#2160) * objects: partially revert e54703519 Since this change you are no longer able to create objects with a / in them to create pseudo-folders. This behavior is relied upon by kOps documented as broken in kubernetes/kops#9933. fixes #2159. * object storage: continuation of partially reverting e547035 Co-authored-by: Joe Topjian --- .../objectstorage/v1/containers_test.go | 2 +- .../objectstorage/v1/objects_test.go | 22 +++++++++---------- .../objectstorage/v1/containers/requests.go | 11 +++++----- .../objectstorage/v1/containers/results.go | 2 +- .../objectstorage/v1/objects/requests.go | 22 ++++++++----------- 5 files changed, 27 insertions(+), 32 deletions(-) diff --git a/acceptance/openstack/objectstorage/v1/containers_test.go b/acceptance/openstack/objectstorage/v1/containers_test.go index c6f1b6a67c..1152fd3dc8 100644 --- a/acceptance/openstack/objectstorage/v1/containers_test.go +++ b/acceptance/openstack/objectstorage/v1/containers_test.go @@ -173,7 +173,7 @@ func TestBulkDeleteContainers(t *testing.T) { // Create a slice of random container names. cNames := make([]string, numContainers) for i := 0; i < numContainers; i++ { - cNames[i] = tools.RandomString("test&happy?-", 8) + cNames[i] = tools.RandomString("gophercloud-test-container-", 8) } // Create numContainers containers. diff --git a/acceptance/openstack/objectstorage/v1/objects_test.go b/acceptance/openstack/objectstorage/v1/objects_test.go index f3f77d36c1..1b61324665 100644 --- a/acceptance/openstack/objectstorage/v1/objects_test.go +++ b/acceptance/openstack/objectstorage/v1/objects_test.go @@ -290,22 +290,22 @@ func TestObjectsBulkDelete(t *testing.T) { } // Create a random subdirectory name. - cSubdir1 := tools.RandomString("don't worry & be happy?-", 8) - cSubdir2 := tools.RandomString("don't worry & be happy?-", 8) + cSubdir1 := tools.RandomString("test-subdir-", 8) + cSubdir2 := tools.RandomString("test-subdir-", 8) // Make a slice of length numObjects to hold the random object names. oNames1 := make([]string, numObjects) for i := 0; i < len(oNames1); i++ { - oNames1[i] = cSubdir1 + "/" + tools.RandomString("stranger?things-", 8) + oNames1[i] = cSubdir1 + "/" + tools.RandomString("test-object-", 8) } oNames2 := make([]string, numObjects) for i := 0; i < len(oNames2); i++ { - oNames2[i] = cSubdir2 + "/" + tools.RandomString("freddy's coming for you?-", 8) + oNames2[i] = cSubdir2 + "/" + tools.RandomString("test-object-", 8) } // Create a container to hold the test objects. - cName := tools.RandomString("test&happy?-", 8) + cName := tools.RandomString("test-container-", 8) _, err = containers.Create(client, cName, nil).Extract() th.AssertNoErr(t, err) @@ -327,12 +327,6 @@ func TestObjectsBulkDelete(t *testing.T) { th.AssertNoErr(t, res.Err) } - expectedResp := objects.BulkDeleteResponse{ - ResponseStatus: "200 OK", - Errors: [][]string{}, - NumberDeleted: numObjects * 2, - } - oContents2 := make([]*bytes.Buffer, numObjects) for i := 0; i < numObjects; i++ { oContents2[i] = bytes.NewBuffer([]byte(tools.RandomString("", 10))) @@ -344,6 +338,12 @@ func TestObjectsBulkDelete(t *testing.T) { } // Delete the objects after testing. + expectedResp := objects.BulkDeleteResponse{ + ResponseStatus: "200 OK", + Errors: [][]string{}, + NumberDeleted: numObjects * 2, + } + resp, err := objects.BulkDelete(client, cName, append(oNames1, oNames2...)).Extract() th.AssertNoErr(t, err) th.AssertDeepEquals(t, *resp, expectedResp) diff --git a/openstack/objectstorage/v1/containers/requests.go b/openstack/objectstorage/v1/containers/requests.go index 119e06997f..bea0d9575c 100644 --- a/openstack/objectstorage/v1/containers/requests.go +++ b/openstack/objectstorage/v1/containers/requests.go @@ -1,7 +1,6 @@ package containers import ( - "net/url" "strings" "github.com/gophercloud/gophercloud" @@ -108,7 +107,7 @@ func Create(c *gophercloud.ServiceClient, containerName string, opts CreateOptsB h[k] = v } } - resp, err := c.Request("PUT", createURL(c, url.QueryEscape(containerName)), &gophercloud.RequestOpts{ + resp, err := c.Request("PUT", createURL(c, containerName), &gophercloud.RequestOpts{ MoreHeaders: h, OkCodes: []int{201, 202, 204}, }) @@ -123,7 +122,7 @@ func BulkDelete(c *gophercloud.ServiceClient, containers []string) (r BulkDelete // https://github.com/openstack/swift/blob/stable/train/swift/common/swob.py#L302 encodedContainers := make([]string, len(containers)) for i, v := range containers { - encodedContainers[i] = url.QueryEscape(v) + encodedContainers[i] = v } b := strings.NewReader(strings.Join(encodedContainers, "\n") + "\n") resp, err := c.Post(bulkDeleteURL(c), b, &r.Body, &gophercloud.RequestOpts{ @@ -139,7 +138,7 @@ func BulkDelete(c *gophercloud.ServiceClient, containers []string) (r BulkDelete // Delete is a function that deletes a container. func Delete(c *gophercloud.ServiceClient, containerName string) (r DeleteResult) { - resp, err := c.Delete(deleteURL(c, url.QueryEscape(containerName)), nil) + resp, err := c.Delete(deleteURL(c, containerName), nil) _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return } @@ -202,7 +201,7 @@ func Update(c *gophercloud.ServiceClient, containerName string, opts UpdateOptsB h[k] = v } } - resp, err := c.Request("POST", updateURL(c, url.QueryEscape(containerName)), &gophercloud.RequestOpts{ + resp, err := c.Request("POST", updateURL(c, containerName), &gophercloud.RequestOpts{ MoreHeaders: h, OkCodes: []int{201, 202, 204}, }) @@ -242,7 +241,7 @@ func Get(c *gophercloud.ServiceClient, containerName string, opts GetOptsBuilder h[k] = v } } - resp, err := c.Head(getURL(c, url.QueryEscape(containerName)), &gophercloud.RequestOpts{ + resp, err := c.Head(getURL(c, containerName), &gophercloud.RequestOpts{ MoreHeaders: h, OkCodes: []int{200, 204}, }) diff --git a/openstack/objectstorage/v1/containers/results.go b/openstack/objectstorage/v1/containers/results.go index 14e390541f..e032640d6f 100644 --- a/openstack/objectstorage/v1/containers/results.go +++ b/openstack/objectstorage/v1/containers/results.go @@ -72,7 +72,7 @@ func ExtractNames(page pagination.Page) ([]string, error) { names = append(names, container.Name) } return names, nil - case strings.HasPrefix(ct, "text/plain"): + case strings.HasPrefix(ct, "text/plain") || ct == "": names := make([]string, 0, 50) body := string(page.(ContainerPage).Body.([]uint8)) diff --git a/openstack/objectstorage/v1/objects/requests.go b/openstack/objectstorage/v1/objects/requests.go index 7d6eb4123a..e820026a2e 100644 --- a/openstack/objectstorage/v1/objects/requests.go +++ b/openstack/objectstorage/v1/objects/requests.go @@ -8,7 +8,6 @@ import ( "fmt" "io" "io/ioutil" - "net/url" "strings" "time" @@ -54,7 +53,7 @@ func (opts ListOpts) ToObjectListParams() (bool, string, error) { func List(c *gophercloud.ServiceClient, containerName string, opts ListOptsBuilder) pagination.Pager { headers := map[string]string{"Accept": "text/plain", "Content-Type": "text/plain"} - url := listURL(c, url.QueryEscape(containerName)) + url := listURL(c, containerName) if opts != nil { full, query, err := opts.ToObjectListParams() if err != nil { @@ -119,7 +118,7 @@ func (opts DownloadOpts) ToObjectDownloadParams() (map[string]string, string, er // To extract just the content, pass the DownloadResult response to the // ExtractContent function. func Download(c *gophercloud.ServiceClient, containerName, objectName string, opts DownloadOptsBuilder) (r DownloadResult) { - url := downloadURL(c, url.QueryEscape(containerName), url.QueryEscape(objectName)) + url := downloadURL(c, containerName, objectName) h := make(map[string]string) if opts != nil { headers, query, err := opts.ToObjectDownloadParams() @@ -225,7 +224,7 @@ func (opts CreateOpts) ToObjectCreateParams() (io.Reader, map[string]string, str // checksum, the failed request will automatically be retried up to a maximum // of 3 times. func Create(c *gophercloud.ServiceClient, containerName, objectName string, opts CreateOptsBuilder) (r CreateResult) { - url := createURL(c, url.QueryEscape(containerName), url.QueryEscape(objectName)) + url := createURL(c, containerName, objectName) h := make(map[string]string) var b io.Reader if opts != nil { @@ -289,7 +288,7 @@ func Copy(c *gophercloud.ServiceClient, containerName, objectName string, opts C h[k] = v } - url := copyURL(c, url.QueryEscape(containerName), url.QueryEscape(objectName)) + url := copyURL(c, containerName, objectName) resp, err := c.Request("COPY", url, &gophercloud.RequestOpts{ MoreHeaders: h, OkCodes: []int{201}, @@ -317,7 +316,7 @@ func (opts DeleteOpts) ToObjectDeleteQuery() (string, error) { // Delete is a function that deletes an object. func Delete(c *gophercloud.ServiceClient, containerName, objectName string, opts DeleteOptsBuilder) (r DeleteResult) { - url := deleteURL(c, url.QueryEscape(containerName), url.QueryEscape(objectName)) + url := deleteURL(c, containerName, objectName) if opts != nil { query, err := opts.ToObjectDeleteQuery() if err != nil { @@ -362,7 +361,7 @@ func (opts GetOpts) ToObjectGetParams() (map[string]string, string, error) { // the custom metadata, pass the GetResult response to the ExtractMetadata // function. func Get(c *gophercloud.ServiceClient, containerName, objectName string, opts GetOptsBuilder) (r GetResult) { - url := getURL(c, url.QueryEscape(containerName), url.QueryEscape(objectName)) + url := getURL(c, containerName, objectName) h := make(map[string]string) if opts != nil { headers, query, err := opts.ToObjectGetParams() @@ -434,7 +433,7 @@ func Update(c *gophercloud.ServiceClient, containerName, objectName string, opts h[k] = v } } - url := updateURL(c, url.QueryEscape(containerName), url.QueryEscape(objectName)) + url := updateURL(c, containerName, objectName) resp, err := c.Post(url, nil, nil, &gophercloud.RequestOpts{ MoreHeaders: h, }) @@ -489,7 +488,7 @@ func CreateTempURL(c *gophercloud.ServiceClient, containerName, objectName strin duration := time.Duration(opts.TTL) * time.Second expiry := date.Add(duration).Unix() - getHeader, err := containers.Get(c, url.QueryEscape(containerName), nil).Extract() + getHeader, err := containers.Get(c, containerName, nil).Extract() if err != nil { return "", err } @@ -521,10 +520,7 @@ func BulkDelete(c *gophercloud.ServiceClient, container string, objects []string // https://github.com/openstack/swift/blob/stable/train/swift/common/swob.py#L302 encodedObjects := make([]string, len(objects)) for i, v := range objects { - encodedObjects[i] = strings.Join([]string{ - url.QueryEscape(container), - url.QueryEscape(v)}, - "/") + encodedObjects[i] = strings.Join([]string{container, v}, "/") } b := strings.NewReader(strings.Join(encodedObjects, "\n") + "\n") resp, err := c.Post(bulkDeleteURL(c), b, &r.Body, &gophercloud.RequestOpts{ From 05c2cc82de67f340d06209fc3b1f5aadac9434c9 Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Tue, 8 Jun 2021 12:33:18 -0600 Subject: [PATCH 23/26] Update CHANGELOG.md --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 906ca7dca9..d3ab856883 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,13 @@ ## 0.18.0 (Unreleased) +NOTES / BREAKING CHANGES + +* As of [GH-2160](https://github.com/gophercloud/gophercloud/pull/2160), Gophercloud no longer URL encodes Object Storage containers and object names. You can still encode them yourself before passing the names to the Object Storage functions. + BUG FIXES * Fixed expected OK codes to use default codes [GH-2173](https://github.com/gophercloud/gophercloud/pull/2173) +* Fixed inablity to create sub-containers (objects with `/` in their name) [GH-2160](https://github.com/gophercloud/gophercloud/pull/2160) IMPROVEMENTS From 08e135ab594d230d9277ef73b8e0677c5c911e65 Mon Sep 17 00:00:00 2001 From: Bob Fournier Date: Thu, 10 Jun 2021 16:27:08 -0400 Subject: [PATCH 24/26] Add support for bios settings options to get additional fields (#2174) For #2166 A recent change to Ironic (https://review.opendev.org/c/openstack/ironic/+/786707) has added support for bios registry fields in the Ironic API. These can be retrieved using the `?detail=True` option. --- openstack/baremetal/v1/nodes/requests.go | 41 ++++- openstack/baremetal/v1/nodes/results.go | 31 ++++ .../baremetal/v1/nodes/testing/fixtures.go | 145 ++++++++++++++++++ .../v1/nodes/testing/requests_test.go | 28 +++- 4 files changed, 242 insertions(+), 3 deletions(-) diff --git a/openstack/baremetal/v1/nodes/requests.go b/openstack/baremetal/v1/nodes/requests.go index 33a649cd9b..7c9befb161 100644 --- a/openstack/baremetal/v1/nodes/requests.go +++ b/openstack/baremetal/v1/nodes/requests.go @@ -640,9 +640,46 @@ func SetRAIDConfig(client *gophercloud.ServiceClient, id string, raidConfigOptsB return } +// ListBIOSSettingsOptsBuilder allows extensions to add additional parameters to the +// ListBIOSSettings request. +type ListBIOSSettingsOptsBuilder interface { + ToListBIOSSettingsOptsQuery() (string, error) +} + +// ListBIOSSettingsOpts defines query options that can be passed to ListBIOSettings +type ListBIOSSettingsOpts struct { + // Provide additional information for the BIOS Settings + Detail bool `q:"detail"` + + // One or more fields to be returned in the response. + Fields []string `q:"fields"` +} + +// ToListBIOSSettingsOptsQuery formats a ListBIOSSettingsOpts into a query string +func (opts ListBIOSSettingsOpts) ToListBIOSSettingsOptsQuery() (string, error) { + if opts.Detail == true && len(opts.Fields) > 0 { + return "", fmt.Errorf("cannot have both fields and detail options for BIOS settings") + } + + q, err := gophercloud.BuildQueryString(opts) + return q.String(), err +} + // Get the current BIOS Settings for the given Node. -func ListBIOSSettings(client *gophercloud.ServiceClient, id string) (r ListBIOSSettingsResult) { - resp, err := client.Get(biosListSettingsURL(client, id), &r.Body, &gophercloud.RequestOpts{ +// To use the opts requires microversion 1.74. +func ListBIOSSettings(client *gophercloud.ServiceClient, id string, opts ListBIOSSettingsOptsBuilder) (r ListBIOSSettingsResult) { + url := biosListSettingsURL(client, id) + if opts != nil { + + query, err := opts.ToListBIOSSettingsOptsQuery() + if err != nil { + r.Err = err + return + } + url += query + } + + resp, err := client.Get(url, &r.Body, &gophercloud.RequestOpts{ OkCodes: []int{200}, }) _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) diff --git a/openstack/baremetal/v1/nodes/results.go b/openstack/baremetal/v1/nodes/results.go index 6566b141a0..1d1e50ffc1 100644 --- a/openstack/baremetal/v1/nodes/results.go +++ b/openstack/baremetal/v1/nodes/results.go @@ -354,6 +354,37 @@ type BIOSSetting struct { // Value of the BIOS setting. Value string `json:"value"` + + // The following fields are returned in microversion 1.74 or later + // when using the `details` option + + // The type of setting - Enumeration, String, Integer, or Boolean. + AttributeType string `json:"attribute_type"` + + // The allowable value for an Enumeration type setting. + AllowableValues []string `json:"allowable_values"` + + // The lowest value for an Integer type setting. + LowerBound *int `json:"lower_bound"` + + // The highest value for an Integer type setting. + UpperBound *int `json:"upper_bound"` + + // Minimum length for a String type setting. + MinLength *int `json:"min_length"` + + // Maximum length for a String type setting. + MaxLength *int `json:"max_length"` + + // Whether or not this setting is read only. + ReadOnly *bool `json:"read_only"` + + // Whether or not a reset is required after changing this setting. + ResetRequired *bool `json:"reset_required"` + + // Whether or not this setting's value is unique to this node, e.g. + // a serial number. + Unique *bool `json:"unique"` } type SingleBIOSSetting struct { diff --git a/openstack/baremetal/v1/nodes/testing/fixtures.go b/openstack/baremetal/v1/nodes/testing/fixtures.go index 157d338b61..39499e7bcd 100644 --- a/openstack/baremetal/v1/nodes/testing/fixtures.go +++ b/openstack/baremetal/v1/nodes/testing/fixtures.go @@ -622,6 +622,92 @@ const NodeBIOSSettingsBody = ` ] } ` + +const NodeDetailBIOSSettingsBody = ` +{ + "bios": [ + { + "created_at": "2021-05-11T21:33:44+00:00", + "updated_at": null, + "name": "Proc1L2Cache", + "value": "10x256 KB", + "attribute_type": "String", + "allowable_values": [], + "lower_bound": null, + "max_length": 16, + "min_length": 0, + "read_only": true, + "reset_required": null, + "unique": null, + "upper_bound": null, + "links": [ + { + "href": "http://ironic.example.com:6385/v1/nodes/d26115bf-1296-4ca8-8c86-6f310d8ec375/bios/Proc1L2Cache", + "rel": "self" + }, + { + "href": "http://ironic.example.com:6385/nodes/d26115bf-1296-4ca8-8c86-6f310d8ec375/bios/Proc1L2Cache", + "rel": "bookmark" + } + ] + }, + { + "created_at": "2021-05-11T21:33:44+00:00", + "updated_at": null, + "name": "Proc1NumCores", + "value": "10", + "attribute_type": "Integer", + "allowable_values": [], + "lower_bound": 0, + "max_length": null, + "min_length": null, + "read_only": true, + "reset_required": null, + "unique": null, + "upper_bound": 20, + "links": [ + { + "href": "http://ironic.example.com:6385/v1/nodes/d26115bf-1296-4ca8-8c86-6f310d8ec375/bios/Proc1NumCores", + "rel": "self" + }, + { + "href": "http://ironic.example.com:6385/nodes/d26115bf-1296-4ca8-8c86-6f310d8ec375/bios/Proc1NumCores", + "rel": "bookmark" + } + ] + }, + { + "created_at": "2021-05-11T21:33:44+00:00", + "updated_at": null, + "name": "ProcVirtualization", + "value": "Enabled", + "attribute_type": "Enumeration", + "allowable_values": [ + "Enabled", + "Disabled" + ], + "lower_bound": null, + "max_length": null, + "min_length": null, + "read_only": false, + "reset_required": null, + "unique": null, + "upper_bound": null, + "links": [ + { + "href": "http://ironic.example.com:6385/v1/nodes/d26115bf-1296-4ca8-8c86-6f310d8ec375/bios/ProcVirtualization", + "rel": "self" + }, + { + "href": "http://ironic.example.com:6385/nodes/d26115bf-1296-4ca8-8c86-6f310d8ec375/bios/ProcVirtualization", + "rel": "bookmark" + } + ] + } + ] +} +` + const NodeSingleBIOSSettingBody = ` { "Setting": { @@ -854,6 +940,55 @@ var ( }, } + iTrue = true + iFalse = false + minLength = 0 + maxLength = 16 + lowerBound = 0 + upperBound = 20 + + NodeDetailBIOSSettings = []nodes.BIOSSetting{ + { + Name: "Proc1L2Cache", + Value: "10x256 KB", + AttributeType: "String", + AllowableValues: []string{}, + LowerBound: nil, + UpperBound: nil, + MinLength: &minLength, + MaxLength: &maxLength, + ReadOnly: &iTrue, + ResetRequired: nil, + Unique: nil, + }, + { + Name: "Proc1NumCores", + Value: "10", + AttributeType: "Integer", + AllowableValues: []string{}, + LowerBound: &lowerBound, + UpperBound: &upperBound, + MinLength: nil, + MaxLength: nil, + ReadOnly: &iTrue, + ResetRequired: nil, + Unique: nil, + }, + { + Name: "ProcVirtualization", + Value: "Enabled", + AttributeType: "Enumeration", + AllowableValues: []string{"Enabled", "Disabled"}, + LowerBound: nil, + UpperBound: nil, + MinLength: nil, + MaxLength: nil, + ReadOnly: &iFalse, + ResetRequired: nil, + Unique: nil, + }, + } + NodeSingleBIOSSetting = nodes.BIOSSetting{ Name: "ProcVirtualization", Value: "Enabled", @@ -1126,6 +1261,16 @@ func HandleListBIOSSettingsSuccessfully(t *testing.T) { }) } +func HandleListDetailBIOSSettingsSuccessfully(t *testing.T) { + th.Mux.HandleFunc("/nodes/1234asdf/bios", 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.Fprintf(w, NodeDetailBIOSSettingsBody) + }) +} + func HandleGetBIOSSettingSuccessfully(t *testing.T) { th.Mux.HandleFunc("/nodes/1234asdf/bios/ProcVirtualization", func(w http.ResponseWriter, r *http.Request) { th.TestMethod(t, r, "GET") diff --git a/openstack/baremetal/v1/nodes/testing/requests_test.go b/openstack/baremetal/v1/nodes/testing/requests_test.go index a912d32660..46e02eb496 100644 --- a/openstack/baremetal/v1/nodes/testing/requests_test.go +++ b/openstack/baremetal/v1/nodes/testing/requests_test.go @@ -552,11 +552,26 @@ func TestListBIOSSettings(t *testing.T) { HandleListBIOSSettingsSuccessfully(t) c := client.ServiceClient() - actual, err := nodes.ListBIOSSettings(c, "1234asdf").Extract() + actual, err := nodes.ListBIOSSettings(c, "1234asdf", nil).Extract() th.AssertNoErr(t, err) th.CheckDeepEquals(t, NodeBIOSSettings, actual) } +func TestListDetailBIOSSettings(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + HandleListDetailBIOSSettingsSuccessfully(t) + + opts := nodes.ListBIOSSettingsOpts{ + Detail: true, + } + + c := client.ServiceClient() + actual, err := nodes.ListBIOSSettings(c, "1234asdf", opts).Extract() + th.AssertNoErr(t, err) + th.CheckDeepEquals(t, NodeDetailBIOSSettings, actual) +} + func TestGetBIOSSetting(t *testing.T) { th.SetupHTTP() defer th.TeardownHTTP() @@ -567,3 +582,14 @@ func TestGetBIOSSetting(t *testing.T) { th.AssertNoErr(t, err) th.CheckDeepEquals(t, NodeSingleBIOSSetting, *actual) } + +func TestListBIOSSettingsOpts(t *testing.T) { + // Detail cannot take Fields + opts := nodes.ListBIOSSettingsOpts{ + Detail: true, + Fields: []string{"name", "value"}, + } + + _, err := opts.ToListBIOSSettingsOptsQuery() + th.AssertEquals(t, err.Error(), "cannot have both fields and detail options for BIOS settings") +} From e16426402d890d19cd27edb30bebf583e5113013 Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Thu, 10 Jun 2021 14:30:21 -0600 Subject: [PATCH 25/26] Update CHANGELOG.md --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d3ab856883..b16b1fabf3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ NOTES / BREAKING CHANGES * As of [GH-2160](https://github.com/gophercloud/gophercloud/pull/2160), Gophercloud no longer URL encodes Object Storage containers and object names. You can still encode them yourself before passing the names to the Object Storage functions. +* `baremetal/v1/nodes.ListBIOSSettings` now takes three parameters. The third, new, parameter is `ListBIOSSettingsOptsBuilder` [GH-2174](https://github.com/gophercloud/gophercloud/pull/2174) + BUG FIXES * Fixed expected OK codes to use default codes [GH-2173](https://github.com/gophercloud/gophercloud/pull/2173) @@ -25,6 +27,16 @@ IMPROVEMENTS * Added `baremetal/v1/nodes.NodeValidation.BIOS` [GH-2164](https://github.com/gophercloud/gophercloud/pull/2164) * Added `baremetal/v1/nodes.ListBIOSSettings` [GH-2171](https://github.com/gophercloud/gophercloud/pull/2171) * Added `baremetal/v1/nodes.GetBIOSSetting` [GH-2171](https://github.com/gophercloud/gophercloud/pull/2171) +* Added `baremetal/v1/nodes.ListBIOSSettingsOpts` [GH-2174](https://github.com/gophercloud/gophercloud/pull/2174) +* Added `baremetal/v1/nodes.BIOSSetting.AttributeType` [GH-2174](https://github.com/gophercloud/gophercloud/pull/2174) +* Added `baremetal/v1/nodes.BIOSSetting.AllowableValues` [GH-2174](https://github.com/gophercloud/gophercloud/pull/2174) +* Added `baremetal/v1/nodes.BIOSSetting.LowerBound` [GH-2174](https://github.com/gophercloud/gophercloud/pull/2174) +* Added `baremetal/v1/nodes.BIOSSetting.UpperBound` [GH-2174](https://github.com/gophercloud/gophercloud/pull/2174) +* Added `baremetal/v1/nodes.BIOSSetting.MinLength` [GH-2174](https://github.com/gophercloud/gophercloud/pull/2174) +* Added `baremetal/v1/nodes.BIOSSetting.MaxLength` [GH-2174](https://github.com/gophercloud/gophercloud/pull/2174) +* Added `baremetal/v1/nodes.BIOSSetting.ReadOnly` [GH-2174](https://github.com/gophercloud/gophercloud/pull/2174) +* Added `baremetal/v1/nodes.BIOSSetting.ResetRequired` [GH-2174](https://github.com/gophercloud/gophercloud/pull/2174) +* Added `baremetal/v1/nodes.BIOSSetting.Unique` [GH-2174](https://github.com/gophercloud/gophercloud/pull/2174) ## 0.17.0 (April 9, 2021) From b99817b08b69f18f1ac066fb41d4b90e4f2af396 Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Fri, 11 Jun 2021 08:28:51 -0600 Subject: [PATCH 26/26] Update CHANGELOG.md --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b16b1fabf3..e5c9c4e169 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,6 @@ -## 0.18.0 (Unreleased) +## 0.19.0 (Unreleased) + +## 0.18.0 (June 11, 2021) NOTES / BREAKING CHANGES