From 757ad867295a7ab7c0bd904fa7faf7cf70f8a0a3 Mon Sep 17 00:00:00 2001 From: kayrus Date: Sat, 27 Jul 2024 12:15:17 +0200 Subject: [PATCH 01/13] [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 8e1a5babca470170b99f0f1276a817d4002a3cdb Mon Sep 17 00:00:00 2001 From: kayrus Date: Tue, 24 Sep 2024 02:40:00 +0200 Subject: [PATCH 02/13] 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 2765b1ff1f8ed85038aaf4b75a3fcda54327cea7 Mon Sep 17 00:00:00 2001 From: kayrus Date: Mon, 23 Sep 2024 23:00:36 +0200 Subject: [PATCH 03/13] 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 b31521943016f60db5d22c5d77731b5d0878a361 Mon Sep 17 00:00:00 2001 From: kayrus Date: Tue, 24 Sep 2024 01:54:02 +0200 Subject: [PATCH 04/13] 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 113e3c4aaae04f064e1fd71aafb10d1d40abf11d Mon Sep 17 00:00:00 2001 From: kayrus Date: Thu, 26 Sep 2024 22:09:13 +0200 Subject: [PATCH 05/13] [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 02cff14569bfdaa94ff8da80f87f715133a0958e Mon Sep 17 00:00:00 2001 From: kayrus Date: Thu, 26 Sep 2024 23:52:53 +0200 Subject: [PATCH 06/13] [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 a253e3965d81dddf5003badac613f0710dc39c6b Mon Sep 17 00:00:00 2001 From: Pierre Prinetti Date: Fri, 4 Oct 2024 12:09:02 +0200 Subject: [PATCH 07/13] 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 155255fb43..d913173810 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,14 +55,14 @@ 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) } func TestServicesUpdate(t *testing.T) { 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 7970f4435d9a8f607cba9b3e21ebba47534e6764 Mon Sep 17 00:00:00 2001 From: kayrus Date: Fri, 27 Sep 2024 16:30:28 +0200 Subject: [PATCH 08/13] [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 260409965feacf42a5a0da581daa4fe832d243a4 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 09/13] 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 9c67060f0a2f37e89b22344c4e6d11c44bb41482 Mon Sep 17 00:00:00 2001 From: kayrus Date: Thu, 10 Oct 2024 18:02:04 +0200 Subject: [PATCH 10/13] [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 7401f48fddced7aee332bf2c5565da2f87c903ea Mon Sep 17 00:00:00 2001 From: kayrus Date: Wed, 9 Oct 2024 13:51:57 +0200 Subject: [PATCH 11/13] [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 8c111b4837..5d680a642b 100644 --- a/openstack/sharedfilesystems/v2/shares/requests.go +++ b/openstack/sharedfilesystems/v2/shares/requests.go @@ -56,6 +56,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 0d1c2a0a6bece35ed9cd30f0574b1a4158837ea2 Mon Sep 17 00:00:00 2001 From: Pierre Prinetti Date: Thu, 17 Oct 2024 10:23:58 +0200 Subject: [PATCH 12/13] 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 9f84b963d8c249bb4a4fb9ff9df388707e3f1afc Mon Sep 17 00:00:00 2001 From: Pierre Prinetti Date: Fri, 18 Oct 2024 13:42:59 +0200 Subject: [PATCH 13/13] Prepare v2.2.0 --- CHANGELOG.md | 13 +++++++++++++ provider_client.go | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 41f9017aa9..efe2d9f6af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +## v2.2.0 (2024-10-18) + +* [GH-3176](https://github.com/gophercloud/gophercloud/pull/3176) [v2] [containerinfra]: add "MasterLBEnabled" in Cluster results +* [GH-3181](https://github.com/gophercloud/gophercloud/pull/3181) [v2] octavia: add new options to health monitors +* [GH-3182](https://github.com/gophercloud/gophercloud/pull/3182) [v2] octavia: add new security options to pools and listeners +* [GH-3195](https://github.com/gophercloud/gophercloud/pull/3195) [v2] [core]: handle empty response body +* [GH-3196](https://github.com/gophercloud/gophercloud/pull/3196) [v2] [fwaas_v2]: proper ParseResponse handling +* [GH-3198](https://github.com/gophercloud/gophercloud/pull/3198) [v2] compute: Fix expected and actual test results +* [GH-3199](https://github.com/gophercloud/gophercloud/pull/3199) [v2] [octavia] add an ability to filter flavors and flavorprofiles +* [GH-3214](https://github.com/gophercloud/gophercloud/pull/3214) [v2] [manila] add scheduler_hints to the shares CreateOpts +* [GH-3215](https://github.com/gophercloud/gophercloud/pull/3215) [v2] [manila] add share_group_id to share's CreateOpts +* [GH-3219](https://github.com/gophercloud/gophercloud/pull/3219) [v2] docs: Remove outdated godoc + ## v2.1.1 (2024-09-18) * [GH-3161](https://github.com/gophercloud/gophercloud/pull/3161) [v2] fix: create security group rule with any protocol diff --git a/provider_client.go b/provider_client.go index e2cd3c2dad..007266f635 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.1" + DefaultUserAgent = "gophercloud/v2.2.0" DefaultMaxBackoffRetries = 60 )