diff --git a/internal/acceptance/openstack/identity/v3/endpoint_test.go b/internal/acceptance/openstack/identity/v3/endpoint_test.go index ae2254102a..8dd9e5bad1 100644 --- a/internal/acceptance/openstack/identity/v3/endpoint_test.go +++ b/internal/acceptance/openstack/identity/v3/endpoint_test.go @@ -39,6 +39,29 @@ func TestEndpointsList(t *testing.T) { th.AssertEquals(t, found, true) } +func TestEndpointsGet(t *testing.T) { + clients.RequireAdmin(t) + + client, err := clients.NewIdentityV3Client() + th.AssertNoErr(t, err) + + allPages, err := endpoints.List(client, nil).AllPages(context.TODO()) + th.AssertNoErr(t, err) + + allEndpoints, err := endpoints.ExtractEndpoints(allPages) + th.AssertNoErr(t, err) + + endpoint := allEndpoints[0] + e, err := endpoints.Get(context.TODO(), client, endpoint.ID).Extract() + if err != nil { + t.Fatalf("Unable to get endpoint: %v", err) + } + + tools.PrintResource(t, e) + + th.AssertEquals(t, e.Name, e.Name) +} + func TestEndpointsNavigateCatalog(t *testing.T) { clients.RequireAdmin(t) diff --git a/openstack/identity/v3/endpoints/requests.go b/openstack/identity/v3/endpoints/requests.go index 35eb966077..4386bb9bc9 100644 --- a/openstack/identity/v3/endpoints/requests.go +++ b/openstack/identity/v3/endpoints/requests.go @@ -90,6 +90,13 @@ func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pa }) } +// Get retrieves details on a single endpoint, by ID. +func Get(ctx context.Context, client *gophercloud.ServiceClient, id string) (r GetResult) { + resp, err := client.Get(ctx, endpointURL(client, id), &r.Body, nil) + _, r.Header, r.Err = gophercloud.ParseResponse(resp, err) + return +} + // UpdateOptsBuilder allows extensions to add parameters to the Update request. type UpdateOptsBuilder interface { ToEndpointUpdateMap() (map[string]any, error) diff --git a/openstack/identity/v3/endpoints/results.go b/openstack/identity/v3/endpoints/results.go index 9efec30af2..19d279ebc6 100644 --- a/openstack/identity/v3/endpoints/results.go +++ b/openstack/identity/v3/endpoints/results.go @@ -19,6 +19,12 @@ func (r commonResult) Extract() (*Endpoint, error) { return s.Endpoint, err } +// GetResult is the response from a Get operation. Call its Extract method +// to interpret it as an Endpoint. +type GetResult struct { + commonResult +} + // CreateResult is the response from a Create operation. Call its Extract // method to interpret it as an Endpoint. type CreateResult struct { diff --git a/openstack/identity/v3/endpoints/testing/requests_test.go b/openstack/identity/v3/endpoints/testing/requests_test.go index 348a1f1c6e..ad138acd49 100644 --- a/openstack/identity/v3/endpoints/testing/requests_test.go +++ b/openstack/identity/v3/endpoints/testing/requests_test.go @@ -20,35 +20,31 @@ func TestCreateSuccessful(t *testing.T) { th.Mux.HandleFunc("/endpoints", func(w http.ResponseWriter, r *http.Request) { th.TestMethod(t, r, "POST") th.TestHeader(t, r, "X-Auth-Token", client.TokenID) - th.TestJSONRequest(t, r, ` - { - "endpoint": { - "interface": "public", - "name": "the-endiest-of-points", - "region": "underground", - "url": "https://1.2.3.4:9000/", - "service_id": "asdfasdfasdfasdf" - } - } - `) + th.TestJSONRequest(t, r, `{ + "endpoint": { + "interface": "public", + "name": "the-endiest-of-points", + "region": "underground", + "url": "https://1.2.3.4:9000/", + "service_id": "asdfasdfasdfasdf" + } + }`) w.WriteHeader(http.StatusCreated) - fmt.Fprint(w, ` - { - "endpoint": { - "id": "12", - "interface": "public", - "enabled": true, - "links": { - "self": "https://localhost:5000/v3/endpoints/12" - }, - "name": "the-endiest-of-points", - "region": "underground", - "service_id": "asdfasdfasdfasdf", - "url": "https://1.2.3.4:9000/" - } - } - `) + fmt.Fprint(w, `{ + "endpoint": { + "id": "12", + "interface": "public", + "enabled": true, + "links": { + "self": "https://localhost:5000/v3/endpoints/12" + }, + "name": "the-endiest-of-points", + "region": "underground", + "service_id": "asdfasdfasdfasdf", + "url": "https://1.2.3.4:9000/" + } + }`) }) actual, err := endpoints.Create(context.TODO(), client.ServiceClient(), endpoints.CreateOpts{ @@ -82,40 +78,38 @@ func TestListEndpoints(t *testing.T) { th.TestHeader(t, r, "X-Auth-Token", client.TokenID) w.Header().Add("Content-Type", "application/json") - fmt.Fprint(w, ` - { - "endpoints": [ - { - "id": "12", - "interface": "public", - "enabled": true, - "links": { - "self": "https://localhost:5000/v3/endpoints/12" - }, - "name": "the-endiest-of-points", - "region": "underground", - "service_id": "asdfasdfasdfasdf", - "url": "https://1.2.3.4:9000/" + fmt.Fprint(w, `{ + "endpoints": [ + { + "id": "12", + "interface": "public", + "enabled": true, + "links": { + "self": "https://localhost:5000/v3/endpoints/12" }, - { - "id": "13", - "interface": "internal", - "enabled": false, - "links": { - "self": "https://localhost:5000/v3/endpoints/13" - }, - "name": "shhhh", - "region": "underground", - "service_id": "asdfasdfasdfasdf", - "url": "https://1.2.3.4:9001/" - } - ], - "links": { - "next": null, - "previous": null + "name": "the-endiest-of-points", + "region": "underground", + "service_id": "asdfasdfasdfasdf", + "url": "https://1.2.3.4:9000/" + }, + { + "id": "13", + "interface": "internal", + "enabled": false, + "links": { + "self": "https://localhost:5000/v3/endpoints/13" + }, + "name": "shhhh", + "region": "underground", + "service_id": "asdfasdfasdfasdf", + "url": "https://1.2.3.4:9001/" } + ], + "links": { + "next": null, + "previous": null } - `) + }`) }) count := 0 @@ -154,6 +148,47 @@ func TestListEndpoints(t *testing.T) { th.AssertEquals(t, 1, count) } +func TestGetEndpoint(t *testing.T) { + th.SetupHTTP() + defer th.TeardownHTTP() + + th.Mux.HandleFunc("/endpoints/12", func(w http.ResponseWriter, r *http.Request) { + th.TestMethod(t, r, "GET") + th.TestHeader(t, r, "X-Auth-Token", client.TokenID) + + fmt.Fprint(w, `{ + "endpoint": { + "id": "12", + "interface": "public", + "enabled": true, + "links": { + "self": "https://localhost:5000/v3/endpoints/12" + }, + "name": "the-endiest-of-points", + "region": "underground", + "service_id": "asdfasdfasdfasdf", + "url": "https://1.2.3.4:9000/" + } + }`) + }) + + actual, err := endpoints.Get(context.TODO(), client.ServiceClient(), "12").Extract() + if err != nil { + t.Fatalf("Unexpected error from Get: %v", err) + } + + expected := &endpoints.Endpoint{ + ID: "12", + Availability: gophercloud.AvailabilityPublic, + Enabled: true, + Name: "the-endiest-of-points", + Region: "underground", + ServiceID: "asdfasdfasdfasdf", + URL: "https://1.2.3.4:9000/", + } + th.AssertDeepEquals(t, expected, actual) +} + func TestUpdateEndpoint(t *testing.T) { th.SetupHTTP() defer th.TeardownHTTP() @@ -161,17 +196,14 @@ func TestUpdateEndpoint(t *testing.T) { th.Mux.HandleFunc("/endpoints/12", func(w http.ResponseWriter, r *http.Request) { th.TestMethod(t, r, "PATCH") th.TestHeader(t, r, "X-Auth-Token", client.TokenID) - th.TestJSONRequest(t, r, ` - { - "endpoint": { - "name": "renamed", + th.TestJSONRequest(t, r, `{ + "endpoint": { + "name": "renamed", "region": "somewhere-else" - } - } - `) + } + }`) - fmt.Fprint(w, ` - { + fmt.Fprint(w, `{ "endpoint": { "id": "12", "interface": "public", @@ -184,8 +216,7 @@ func TestUpdateEndpoint(t *testing.T) { "service_id": "asdfasdfasdfasdf", "url": "https://1.2.3.4:9000/" } - } - `) + }`) }) actual, err := endpoints.Update(context.TODO(), client.ServiceClient(), "12", endpoints.UpdateOpts{ diff --git a/openstack/identity/v3/projects/doc.go b/openstack/identity/v3/projects/doc.go index 6aea466a51..6100327397 100644 --- a/openstack/identity/v3/projects/doc.go +++ b/openstack/identity/v3/projects/doc.go @@ -73,7 +73,7 @@ Example to List all tags of a Project panic(err) } -Example to modify all tags of a Project +Example to modify all tags of a Project projectID := "966b3c7d36a24facaf20b7e458bf2192" tags := ["foo", "bar"]