From 938fcc52c31f7a860d55c899068f9f3631802459 Mon Sep 17 00:00:00 2001 From: Julien Tanguy Date: Fri, 2 Sep 2022 09:46:24 +0000 Subject: [PATCH 1/5] Add NetworkType and SegmentationID filters when list networks --- openstack/networking/v2/networks/requests.go | 34 +++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/openstack/networking/v2/networks/requests.go b/openstack/networking/v2/networks/requests.go index 1565898496..201f5a18d2 100644 --- a/openstack/networking/v2/networks/requests.go +++ b/openstack/networking/v2/networks/requests.go @@ -19,22 +19,24 @@ type ListOptsBuilder interface { // by a particular network attribute. SortDir sets the direction, and is either // `asc' or `desc'. Marker and Limit are used for pagination. type ListOpts struct { - Status string `q:"status"` - Name string `q:"name"` - Description string `q:"description"` - AdminStateUp *bool `q:"admin_state_up"` - TenantID string `q:"tenant_id"` - ProjectID string `q:"project_id"` - Shared *bool `q:"shared"` - ID string `q:"id"` - Marker string `q:"marker"` - Limit int `q:"limit"` - SortKey string `q:"sort_key"` - SortDir string `q:"sort_dir"` - Tags string `q:"tags"` - TagsAny string `q:"tags-any"` - NotTags string `q:"not-tags"` - NotTagsAny string `q:"not-tags-any"` + Status string `q:"status"` + Name string `q:"name"` + Description string `q:"description"` + AdminStateUp *bool `q:"admin_state_up"` + TenantID string `q:"tenant_id"` + ProjectID string `q:"project_id"` + Shared *bool `q:"shared"` + ID string `q:"id"` + Marker string `q:"marker"` + Limit int `q:"limit"` + SortKey string `q:"sort_key"` + SortDir string `q:"sort_dir"` + Tags string `q:"tags"` + TagsAny string `q:"tags-any"` + NotTags string `q:"not-tags"` + NotTagsAny string `q:"not-tags-any"` + NetworkType string `q:"provider:network_type"` + SegmentationID int `q:"provider:segmentation_id"` } // ToNetworkListQuery formats a ListOpts into a query string. From 71b919a188ec8807b8fa45a069b8a663fccee401 Mon Sep 17 00:00:00 2001 From: mdelord <38280771+mdelord@users.noreply.github.com> Date: Fri, 7 Oct 2022 16:01:25 +0200 Subject: [PATCH 2/5] Fix BareMetalV1 version (#16) Co-authored-by: Maxime Delord --- openstack/client.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openstack/client.go b/openstack/client.go index 81c907c35b..d051098eb0 100644 --- a/openstack/client.go +++ b/openstack/client.go @@ -363,7 +363,11 @@ func initClientOpts(client *gophercloud.ProviderClient, eo gophercloud.EndpointO // NewBareMetalV1 creates a ServiceClient that may be used with the v1 // bare metal package. func NewBareMetalV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) { - return initClientOpts(client, eo, "baremetal") + sc, err := initClientOpts(client, eo, "baremetal") + if !strings.HasSuffix(sc.Endpoint, "v1/") { + sc.ResourceBase = sc.Endpoint + "v1/" + } + return sc, err } // NewBareMetalIntrospectionV1 creates a ServiceClient that may be used with the v1 From 418c5c63487b288aea6b4ebb1fae0d23e097b3ca Mon Sep 17 00:00:00 2001 From: Benjamin Ziehms Date: Mon, 16 Jan 2023 15:22:35 +0000 Subject: [PATCH 3/5] feat(identity): add create, update and delete endpoint group --- .../v3/extensions/endpointgroups/requests.go | 91 +++++++++++++++++++ .../v3/extensions/endpointgroups/results.go | 18 ++++ .../v3/extensions/endpointgroups/urls.go | 24 +++-- 3 files changed, 127 insertions(+), 6 deletions(-) diff --git a/openstack/identity/v3/extensions/endpointgroups/requests.go b/openstack/identity/v3/extensions/endpointgroups/requests.go index c121226341..a188376111 100644 --- a/openstack/identity/v3/extensions/endpointgroups/requests.go +++ b/openstack/identity/v3/extensions/endpointgroups/requests.go @@ -76,3 +76,94 @@ func DeleteProjectAssociation(client *gophercloud.ServiceClient, id string, proj _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) return } + +// CreateOptsBuilder allows extensions to add additional parameters to +// the Create request. +type CreateOptsBuilder interface { + ToGroupCreateMap() (map[string]interface{}, error) +} + +// CreateOpts provides options used to create a group. +type CreateOpts struct { + // Name is the name of the new endpoint group. + Name string `json:"name" required:"true"` + + // Description is a description of the endpoint group. + Description *string `json:"description,omitempty"` + + // Filters are the filters of the endpoint group. + Filters map[string]interface{} `json:"filters,omitempty"` +} + +// ToGroupCreateMap formats a CreateOpts into a create request. +func (opts CreateOpts) ToGroupCreateMap() (map[string]interface{}, error) { + b, err := gophercloud.BuildRequestBody(opts, "endpoint_group") + if err != nil { + return nil, err + } + + return b, nil +} + +// Create creates a new endpoint group. +func Create(client *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) { + b, err := opts.ToGroupCreateMap() + if err != nil { + r.Err = err + return + } + resp, err := client.Post(createURL(client), &b, &r.Body, &gophercloud.RequestOpts{ + OkCodes: []int{201}, + }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + +// UpdateOptsBuilder allows extensions to add additional parameters to +// the Update request. +type UpdateOptsBuilder interface { + ToGroupUpdateMap() (map[string]interface{}, error) +} + +// UpdateOpts provides options for updating an endpoint group. +type UpdateOpts struct { + // Name is the name of the endpoint group. + Name string `json:"name,omitempty"` + + // Description is a description of the endpoint group. + Description *string `json:"description,omitempty"` + + // Filters are the filters of the endpoint group. + Filters map[string]interface{} `json:"filters,omitempty"` +} + +// ToGroupUpdateMap formats a UpdateOpts into an update request. +func (opts UpdateOpts) ToGroupUpdateMap() (map[string]interface{}, error) { + b, err := gophercloud.BuildRequestBody(opts, "endpoint_group") + if err != nil { + return nil, err + } + + return b, nil +} + +// Update updates an existing Endpoint Group. +func Update(client *gophercloud.ServiceClient, groupID string, opts UpdateOptsBuilder) (r UpdateResult) { + b, err := opts.ToGroupUpdateMap() + if err != nil { + r.Err = err + return + } + resp, err := client.Patch(updateURL(client, groupID), &b, &r.Body, &gophercloud.RequestOpts{ + OkCodes: []int{200}, + }) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + +// Delete deletes an endpoint group. +func Delete(client *gophercloud.ServiceClient, groupID string) (r DeleteResult) { + resp, err := client.Delete(deleteURL(client, groupID), nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} diff --git a/openstack/identity/v3/extensions/endpointgroups/results.go b/openstack/identity/v3/extensions/endpointgroups/results.go index 0d8d481640..5585ad4fb7 100644 --- a/openstack/identity/v3/extensions/endpointgroups/results.go +++ b/openstack/identity/v3/extensions/endpointgroups/results.go @@ -73,3 +73,21 @@ type CheckProjectAssociationResult struct { type DeleteProjectAssociationResult struct { gophercloud.ErrResult } + +// CreateResult is the response from a Create operation. Call its Extract method +// to interpret it as an Endpoint Group. +type CreateResult struct { + commonResult +} + +// UpdateResult is the response from an Update operation. Call its Extract +// method to interpret it as an Endpoint Group. +type UpdateResult struct { + commonResult +} + +// DeleteResult is the response from a Delete operation. Call its ExtractErr to +// determine if the request succeeded or failed. +type DeleteResult struct { + gophercloud.ErrResult +} diff --git a/openstack/identity/v3/extensions/endpointgroups/urls.go b/openstack/identity/v3/extensions/endpointgroups/urls.go index 5e0f319146..d3716691b9 100644 --- a/openstack/identity/v3/extensions/endpointgroups/urls.go +++ b/openstack/identity/v3/extensions/endpointgroups/urls.go @@ -11,14 +11,26 @@ func rootURL(client *gophercloud.ServiceClient) string { return client.ServiceURL(endpointGroupPath) } -func resourceURL(client *gophercloud.ServiceClient, endointGroupID string) string { - return client.ServiceURL(endpointGroupPath, endointGroupID) +func resourceURL(client *gophercloud.ServiceClient, endpointGroupID string) string { + return client.ServiceURL(endpointGroupPath, endpointGroupID) } -func projectAssociationURL(client *gophercloud.ServiceClient, endpointGroupId string, projectId string) string { - return client.ServiceURL(endpointGroupPath, endpointGroupId, "projects", projectId) +func projectAssociationURL(client *gophercloud.ServiceClient, endpointGroupID string, projectID string) string { + return client.ServiceURL(endpointGroupPath, endpointGroupID, "projects", projectID) } -func listEndpointGroupsAssociationURL(client *gophercloud.ServiceClient, projectId string) string { - return client.ServiceURL(endpointGroupsAssociationPath, projectId, "endpoint_groups") +func listEndpointGroupsAssociationURL(client *gophercloud.ServiceClient, projectID string) string { + return client.ServiceURL(endpointGroupsAssociationPath, projectID, "endpoint_groups") +} + +func createURL(client *gophercloud.ServiceClient) string { + return client.ServiceURL(endpointGroupPath) +} + +func updateURL(client *gophercloud.ServiceClient, endpointGroupID string) string { + return client.ServiceURL(endpointGroupPath, endpointGroupID) +} + +func deleteURL(client *gophercloud.ServiceClient, endpointGroupID string) string { + return client.ServiceURL(endpointGroupPath, endpointGroupID) } From 485454fe86905f376a584d48772bb4a8ec4d3909 Mon Sep 17 00:00:00 2001 From: Benjamin Ziehms Date: Mon, 16 Jan 2023 15:23:06 +0000 Subject: [PATCH 4/5] feat(identity): add get endpoint by ID --- openstack/identity/v3/endpoints/requests.go | 7 +++++++ openstack/identity/v3/endpoints/results.go | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/openstack/identity/v3/endpoints/requests.go b/openstack/identity/v3/endpoints/requests.go index 4eba57cd9f..01e9f1858d 100644 --- a/openstack/identity/v3/endpoints/requests.go +++ b/openstack/identity/v3/endpoints/requests.go @@ -88,6 +88,13 @@ func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pa }) } +// Get retrieves details on a single endpoint, by ID. +func Get(client *gophercloud.ServiceClient, id string) (r GetResult) { + resp, err := client.Get(endpointURL(client, id), &r.Body, nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + // UpdateOptsBuilder allows extensions to add parameters to the Update request. type UpdateOptsBuilder interface { ToEndpointUpdateMap() (map[string]interface{}, error) diff --git a/openstack/identity/v3/endpoints/results.go b/openstack/identity/v3/endpoints/results.go index 886e1b4987..924abada5d 100644 --- a/openstack/identity/v3/endpoints/results.go +++ b/openstack/identity/v3/endpoints/results.go @@ -19,6 +19,12 @@ func (r commonResult) Extract() (*Endpoint, error) { return s.Endpoint, err } +// GetResult is the response from a Get operation. Call its Extract method +// to interpret it as an Endpoint. +type GetResult struct { + commonResult +} + // CreateResult is the response from a Create operation. Call its Extract // method to interpret it as an Endpoint. type CreateResult struct { From 94fddcf88723336b144d03b727fc3236400f686b Mon Sep 17 00:00:00 2001 From: Ludovic Lamarche Date: Wed, 19 Jul 2023 10:18:27 +0000 Subject: [PATCH 5/5] add loadbalancer additional vips feature --- .../loadbalancer/v2/loadbalancers/requests.go | 4 ++++ .../loadbalancer/v2/loadbalancers/results.go | 10 ++++++++++ .../v2/loadbalancers/testing/fixtures.go | 18 +++++++++++++----- .../v2/loadbalancers/testing/requests_test.go | 6 ++++++ 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/openstack/loadbalancer/v2/loadbalancers/requests.go b/openstack/loadbalancer/v2/loadbalancers/requests.go index 099113c418..94da5ec694 100644 --- a/openstack/loadbalancer/v2/loadbalancers/requests.go +++ b/openstack/loadbalancer/v2/loadbalancers/requests.go @@ -140,6 +140,10 @@ type CreateOpts struct { // Tags is a set of resource tags. Tags []string `json:"tags,omitempty"` + + // The additional ips of the loadbalancer. Subnets must all belong to the same network as the primary VIP. + // New in version 2.26 + AdditionalVIps []AdditionalVip `json:"additional_vips,omitempty"` } // ToLoadBalancerCreateMap builds a request body from CreateOpts. diff --git a/openstack/loadbalancer/v2/loadbalancers/results.go b/openstack/loadbalancer/v2/loadbalancers/results.go index 71f750dd6a..64870d5d39 100644 --- a/openstack/loadbalancer/v2/loadbalancers/results.go +++ b/openstack/loadbalancer/v2/loadbalancers/results.go @@ -77,6 +77,16 @@ type LoadBalancer struct { // Tags is a list of resource tags. Tags are arbitrarily defined strings // attached to the resource. Tags []string `json:"tags"` + + // The additional ips of the loadbalancer. Subnets must all belong to the same network as the primary VIP. + // New in version 2.26 + AdditionalVIps []AdditionalVip `json:"additional_vips"` +} + +// AdditionalVip represent additional ip of a loadbalancer. IpAddress field is optional. +type AdditionalVip struct { + SubnetID string `json:"subnet_id"` + IPAddress string `json:"ip_address,omitempty"` } func (r *LoadBalancer) UnmarshalJSON(b []byte) error { diff --git a/openstack/loadbalancer/v2/loadbalancers/testing/fixtures.go b/openstack/loadbalancer/v2/loadbalancers/testing/fixtures.go index 5a8ce9e362..06e47c7304 100644 --- a/openstack/loadbalancer/v2/loadbalancers/testing/fixtures.go +++ b/openstack/loadbalancer/v2/loadbalancers/testing/fixtures.go @@ -19,7 +19,7 @@ import ( const LoadbalancersListBody = ` { "loadbalancers":[ - { + { "id": "c331058c-6a40-4144-948e-b9fb1df9db4b", "project_id": "54030507-44f7-473c-9342-b4d14a95f692", "created_at": "2019-06-30T04:15:37", @@ -52,7 +52,8 @@ const LoadbalancersListBody = ` "admin_state_up": true, "provisioning_status": "PENDING_CREATE", "operating_status": "OFFLINE", - "tags": ["test", "stage"] + "tags": ["test", "stage"], + "additional_vips": [{"subnet_id": "0d4f6a08-60b7-44ab-8903-f7d76ec54095", "ip_address" : "192.168.10.10"}] } ] } @@ -77,7 +78,8 @@ const SingleLoadbalancerBody = ` "admin_state_up": true, "provisioning_status": "PENDING_CREATE", "operating_status": "OFFLINE", - "tags": ["test", "stage"] + "tags": ["test", "stage"], + "additional_vips": [{"subnet_id": "0d4f6a08-60b7-44ab-8903-f7d76ec54095", "ip_address" : "192.168.10.10"}] } } ` @@ -289,7 +291,12 @@ var ( ProvisioningStatus: "PENDING_CREATE", OperatingStatus: "OFFLINE", Tags: []string{"test", "stage"}, - } + AdditionalVIps: []loadbalancers.AdditionalVip{ + { + SubnetID: "0d4f6a08-60b7-44ab-8903-f7d76ec54095", + IPAddress: "192.168.10.10", + }, + }} LoadbalancerUpdated = loadbalancers.LoadBalancer{ ID: "36e08a3e-a78f-4b40-a229-1e7e23eee1ab", ProjectID: "54030507-44f7-473c-9342-b4d14a95f692", @@ -546,7 +553,8 @@ func HandleLoadbalancerCreationSuccessfully(t *testing.T, response string) { "flavor_id": "bba40eb2-ee8c-11e9-81b4-2a2ae2dbcce4", "provider": "haproxy", "admin_state_up": true, - "tags": ["test", "stage"] + "tags": ["test", "stage"], + "additional_vips": [{"subnet_id": "0d4f6a08-60b7-44ab-8903-f7d76ec54095", "ip_address" : "192.168.10.10"}] } }`) diff --git a/openstack/loadbalancer/v2/loadbalancers/testing/requests_test.go b/openstack/loadbalancer/v2/loadbalancers/testing/requests_test.go index 8a420621bb..1d4831c167 100644 --- a/openstack/loadbalancer/v2/loadbalancers/testing/requests_test.go +++ b/openstack/loadbalancer/v2/loadbalancers/testing/requests_test.go @@ -72,6 +72,12 @@ func TestCreateLoadbalancer(t *testing.T) { FlavorID: "bba40eb2-ee8c-11e9-81b4-2a2ae2dbcce4", Provider: "haproxy", Tags: []string{"test", "stage"}, + AdditionalVIps: []loadbalancers.AdditionalVip{ + { + SubnetID: "0d4f6a08-60b7-44ab-8903-f7d76ec54095", + IPAddress: "192.168.10.10", + }, + }, }).Extract() th.AssertNoErr(t, err)