Skip to content

Commit d987a08

Browse files
authored
Merge pull request #2406 from shhgs/2022-05-20
Neutron v2: AddGatewayNetwork, RemoveGatewayNetwork and GetAdvertised…
2 parents 500e61e + b957a55 commit d987a08

7 files changed

Lines changed: 327 additions & 20 deletions

File tree

acceptance/openstack/networking/v2/extensions/bgp/speakers/bgpspeakers_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"testing"
55

66
"github.com/gophercloud/gophercloud/acceptance/clients"
7+
networking "github.com/gophercloud/gophercloud/acceptance/openstack/networking/v2"
78
ap "github.com/gophercloud/gophercloud/acceptance/openstack/networking/v2/extensions/bgp/peers"
89
"github.com/gophercloud/gophercloud/acceptance/tools"
910
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/bgp/peers"
@@ -34,6 +35,11 @@ func TestBGPSpeakerCRUD(t *testing.T) {
3435
tools.PrintResource(t, allSpeakers)
3536
th.AssertIntGreaterOrEqual(t, len(allSpeakers), 1)
3637

38+
// Create a network
39+
network, err := networking.CreateNetwork(t, client)
40+
th.AssertNoErr(t, err)
41+
defer networking.DeleteNetwork(t, client, network.ID)
42+
3743
// Update BGP Speaker
3844
opts := speakers.UpdateOpts{
3945
Name: tools.RandomString("TESTACC-BGPSPEAKER-", 10),
@@ -69,6 +75,27 @@ func TestBGPSpeakerCRUD(t *testing.T) {
6975
th.AssertEquals(t, len(speakerGot.Networks), 0)
7076
t.Logf("Successfully removed BGP Peer %s to BGP Speaker %s", bgpPeer.Name, speakerUpdated.Name)
7177

78+
// GetAdvertisedRoutes
79+
pages, err := speakers.GetAdvertisedRoutes(client, bgpSpeaker.ID).AllPages()
80+
th.AssertNoErr(t, err)
81+
routes, err := speakers.ExtractAdvertisedRoutes(pages)
82+
th.AssertNoErr(t, err)
83+
th.AssertIntGreaterOrEqual(t, len(routes), 0)
84+
t.Logf("Successfully retrieved advertised routes")
85+
86+
// AddGatewayNetwork
87+
optsAddGatewayNetwork := speakers.AddGatewayNetworkOpts{NetworkID: network.ID}
88+
r, err := speakers.AddGatewayNetwork(client, bgpSpeaker.ID, optsAddGatewayNetwork).Extract()
89+
th.AssertNoErr(t, err)
90+
th.AssertEquals(t, r.NetworkID, network.ID)
91+
t.Logf("Successfully added gateway network %s to BGP Speaker", network.ID)
92+
93+
// RemoveGatewayNetwork
94+
optsRemoveGatewayNetwork := speakers.RemoveGatewayNetworkOpts{NetworkID: network.ID}
95+
err = speakers.RemoveGatewayNetwork(client, bgpSpeaker.ID, optsRemoveGatewayNetwork).ExtractErr()
96+
th.AssertNoErr(t, err)
97+
t.Logf("Successfully removed gateway network %s to BGP Speaker", network.ID)
98+
7299
// Delete a BGP Peer
73100
t.Logf("Delete the BGP Peer %s", bgpPeer.Name)
74101
err = peers.Delete(client, bgpPeer.ID).ExtractErr()

openstack/networking/v2/extensions/bgp/speakers/doc.go

Lines changed: 62 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,14 @@ Example:
3737
3838
Example:
3939
40-
opts := speakers.CreateOpts{
41-
IPVersion: 6,
42-
AdvertiseFloatingIPHostRoutes: false,
43-
AdvertiseTenantNetworks: true,
44-
Name: "gophercloud-testing-bgp-speaker",
45-
LocalAS: "2000",
46-
Networks: []string{},
47-
}
40+
opts := speakers.CreateOpts{
41+
IPVersion: 6,
42+
AdvertiseFloatingIPHostRoutes: false,
43+
AdvertiseTenantNetworks: true,
44+
Name: "gophercloud-testing-bgp-speaker",
45+
LocalAS: "2000",
46+
Networks: []string{},
47+
}
4848
r, err := speakers.Create(c, opts).Extract()
4949
if err != nil {
5050
log.Panic(err)
@@ -67,23 +67,23 @@ Example:
6767
6868
Example:
6969
70-
opts := speakers.UpdateOpts{
71-
Name: "testing-bgp-speaker",
72-
AdvertiseTenantNetworks: false,
73-
AdvertiseFloatingIPHostRoutes: true,
74-
}
75-
spk, err := speakers.Update(c, bgpSpeakerID, opts).Extract()
76-
if err != nil {
77-
log.Panic(err)
78-
}
79-
log.Printf("%+v", spk)
70+
opts := speakers.UpdateOpts{
71+
Name: "testing-bgp-speaker",
72+
AdvertiseTenantNetworks: false,
73+
AdvertiseFloatingIPHostRoutes: true,
74+
}
75+
spk, err := speakers.Update(c, bgpSpeakerID, opts).Extract()
76+
if err != nil {
77+
log.Panic(err)
78+
}
79+
log.Printf("%+v", spk)
8080
8181
8282
7. Add BGP Peer, a.k.a. PUT /bgp-speakers/{id}/add_bgp_peer
8383
8484
Example:
8585
86-
opts := speakers.AddBGPPeerOpts{BGPPeerID: bgpPeerID}
86+
opts := speakers.AddBGPPeerOpts{BGPPeerID: bgpPeerID}
8787
r, err := speakers.AddBGPPeer(c, bgpSpeakerID, opts).Extract()
8888
if err != nil {
8989
log.Panic(err)
@@ -95,10 +95,52 @@ Example:
9595
9696
Example:
9797
98-
opts := speakers.RemoveBGPPeerOpts{BGPPeerID: bgpPeerID}
98+
opts := speakers.RemoveBGPPeerOpts{BGPPeerID: bgpPeerID}
9999
err := speakers.RemoveBGPPeer(c, bgpSpeakerID, opts).ExtractErr()
100100
if err != nil {
101101
log.Panic(err)
102102
}
103103
log.Printf("Successfully removed BGP Peer")
104+
105+
106+
9. Get advertised routes, a.k.a. GET /bgp-speakers/{id}/get_advertised_routes
107+
108+
Example:
109+
110+
pages, err := speakers.GetAdvertisedRoutes(c, speakerID).AllPages()
111+
if err != nil {
112+
log.Panic(err)
113+
}
114+
routes, err := speakers.ExtractAdvertisedRoutes(pages)
115+
if err != nil {
116+
log.Panic(err)
117+
}
118+
for _, r := range routes {
119+
log.Printf("%+v", r)
120+
}
121+
122+
123+
10. Add geteway network to BGP Speaker, a.k.a. PUT /bgp-speakers/{id}/add_gateway_network
124+
125+
Example:
126+
127+
128+
opts := speakers.AddGatewayNetworkOpts{NetworkID: networkID}
129+
r, err := speakers.AddGatewayNetwork(c, speakerID, opts).Extract()
130+
if err != nil {
131+
log.Panic(err)
132+
}
133+
log.Printf("%+v", r)
134+
135+
136+
11. Remove gateway network to BGP Speaker, a.k.a. PUT /bgp-speakers/{id}/remove_gateway_network
137+
138+
Example:
139+
140+
opts := speakers.RemoveGatewayNetworkOpts{NetworkID: networkID}
141+
err := speakers.RemoveGatewayNetwork(c, speakerID, opts).ExtractErr()
142+
if err != nil {
143+
log.Panic(err)
144+
}
145+
log.Printf("Successfully removed gateway network")
104146
*/

openstack/networking/v2/extensions/bgp/speakers/requests.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,3 +146,68 @@ func RemoveBGPPeer(c *gophercloud.ServiceClient, bgpSpeakerID string, opts Remov
146146
_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
147147
return
148148
}
149+
150+
// GetAdvertisedRoutes a.k.a. GET /v2.0/bgp-speakers/{bgp-speaker-id}/get_advertised_routes
151+
func GetAdvertisedRoutes(c *gophercloud.ServiceClient, bgpSpeakerID string) pagination.Pager {
152+
url := getAdvertisedRoutesURL(c, bgpSpeakerID)
153+
return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page {
154+
return AdvertisedRoutePage{pagination.SinglePageBase(r)}
155+
})
156+
}
157+
158+
// AddGatewayNetworkOptsBuilder declare a function that build AddGatewayNetworkOpts into a request body.
159+
type AddGatewayNetworkOptsBuilder interface {
160+
ToBGPSpeakerAddGatewayNetworkMap() (map[string]interface{}, error)
161+
}
162+
163+
// AddGatewayNetworkOpts represents the data that would be PUT to the endpoint
164+
type AddGatewayNetworkOpts struct {
165+
// The uuid of the network
166+
NetworkID string `json:"network_id"`
167+
}
168+
169+
// ToBGPSpeakerAddGatewayNetworkMap implements the function
170+
func (opts AddGatewayNetworkOpts) ToBGPSpeakerAddGatewayNetworkMap() (map[string]interface{}, error) {
171+
return gophercloud.BuildRequestBody(opts, "")
172+
}
173+
174+
// AddGatewayNetwork a.k.a. PUT /v2.0/bgp-speakers/{bgp-speaker-id}/add_gateway_network
175+
func AddGatewayNetwork(c *gophercloud.ServiceClient, bgpSpeakerID string, opts AddGatewayNetworkOptsBuilder) (r AddGatewayNetworkResult) {
176+
b, err := opts.ToBGPSpeakerAddGatewayNetworkMap()
177+
if err != nil {
178+
r.Err = err
179+
return
180+
}
181+
resp, err := c.Put(addGatewayNetworkURL(c, bgpSpeakerID), b, &r.Body, &gophercloud.RequestOpts{
182+
OkCodes: []int{200},
183+
})
184+
_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
185+
return
186+
}
187+
188+
// RemoveGatewayNetworkOptsBuilder declare a function that build RemoveGatewayNetworkOpts into a request body.
189+
type RemoveGatewayNetworkOptsBuilder interface {
190+
ToBGPSpeakerRemoveGatewayNetworkMap() (map[string]interface{}, error)
191+
}
192+
193+
// RemoveGatewayNetworkOpts represent the data that would be PUT to the endpoint
194+
type RemoveGatewayNetworkOpts AddGatewayNetworkOpts
195+
196+
// ToBGPSpeakerRemoveGatewayNetworkMap implement the function
197+
func (opts RemoveGatewayNetworkOpts) ToBGPSpeakerRemoveGatewayNetworkMap() (map[string]interface{}, error) {
198+
return gophercloud.BuildRequestBody(opts, "")
199+
}
200+
201+
// RemoveGatewayNetwork a.k.a. PUT /v2.0/bgp-speakers/{bgp-speaker-id}/remove_gateway_network
202+
func RemoveGatewayNetwork(c *gophercloud.ServiceClient, bgpSpeakerID string, opts RemoveGatewayNetworkOptsBuilder) (r RemoveGatewayNetworkResult) {
203+
b, err := opts.ToBGPSpeakerRemoveGatewayNetworkMap()
204+
if err != nil {
205+
r.Err = err
206+
return
207+
}
208+
resp, err := c.Put(removeGatewayNetworkURL(c, bgpSpeakerID), b, &r.Body, &gophercloud.RequestOpts{
209+
OkCodes: []int{200},
210+
})
211+
_, r.Header, r.Err = gophercloud.ParseResponse(resp, err)
212+
return
213+
}

openstack/networking/v2/extensions/bgp/speakers/results.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,54 @@ func (r AddBGPPeerResult) ExtractInto(v interface{}) error {
128128
type RemoveBGPPeerResult struct {
129129
gophercloud.ErrResult
130130
}
131+
132+
// AdvertisedRoute represents an advertised route
133+
type AdvertisedRoute struct {
134+
// NextHop IP address
135+
NextHop string `json:"next_hop"`
136+
137+
// Destination Network
138+
Destination string `json:"destination"`
139+
}
140+
141+
// AdvertisedRoutePage is the page returned by a pager when you call
142+
type AdvertisedRoutePage struct {
143+
pagination.SinglePageBase
144+
}
145+
146+
// IsEmpty checks whether a AdvertisedRoutePage struct is empty.
147+
func (r AdvertisedRoutePage) IsEmpty() (bool, error) {
148+
is, err := ExtractAdvertisedRoutes(r)
149+
return len(is) == 0, err
150+
}
151+
152+
// ExtractAdvertisedRoutes accepts a Page struct, a.k.a. AdvertisedRoutePage struct,
153+
// and extracts the elements into a slice of AdvertisedRoute structs.
154+
func ExtractAdvertisedRoutes(r pagination.Page) ([]AdvertisedRoute, error) {
155+
var s []AdvertisedRoute
156+
err := ExtractAdvertisedRoutesInto(r, &s)
157+
return s, err
158+
}
159+
160+
// ExtractAdvertisedRoutesInto extract the advertised routes from the first param into the 2nd
161+
func ExtractAdvertisedRoutesInto(r pagination.Page, v interface{}) error {
162+
return r.(AdvertisedRoutePage).Result.ExtractIntoSlicePtr(v, "advertised_routes")
163+
}
164+
165+
// AddGatewayNetworkResult represents the data that would be PUT to
166+
// /v2.0/bgp-speakers/{bgp-speaker-id}/add_gateway_network
167+
type AddGatewayNetworkResult struct {
168+
gophercloud.Result
169+
}
170+
171+
func (r AddGatewayNetworkResult) Extract() (*AddGatewayNetworkOpts, error) {
172+
var s AddGatewayNetworkOpts
173+
err := r.ExtractInto(&s)
174+
return &s, err
175+
}
176+
177+
// RemoveGatewayNetworkResult represents the data that would be PUT to
178+
// /v2.0/bgp-speakers/{bgp-speaker-id}/remove_gateway_network
179+
type RemoveGatewayNetworkResult struct {
180+
gophercloud.ErrResult
181+
}

openstack/networking/v2/extensions/bgp/speakers/testing/fixture.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,3 +122,28 @@ const AddRemoveBGPPeerJSON = `
122122
"bgp_peer_id": "f5884c7c-71d5-43a3-88b4-1742e97674aa"
123123
}
124124
`
125+
126+
const GetAdvertisedRoutesResult = `
127+
{
128+
"advertised_routes": [
129+
{
130+
"next_hop": "172.17.128.212",
131+
"destination": "172.17.129.192/27"
132+
},
133+
{
134+
"next_hop": "172.17.128.218",
135+
"destination": "172.17.129.0/27"
136+
},
137+
{
138+
"next_hop": "172.17.128.231",
139+
"destination": "172.17.129.160/27"
140+
}
141+
]
142+
}
143+
`
144+
145+
const AddRemoveGatewayNetworkJSON = `
146+
{
147+
"network_id": "ac13bb26-6219-49c3-a880-08847f6830b7"
148+
}
149+
`

openstack/networking/v2/extensions/bgp/speakers/testing/requests_test.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,3 +194,85 @@ func TestRemoveBGPPeer(t *testing.T) {
194194
err := speakers.RemoveBGPPeer(fake.ServiceClient(), bgpSpeakerID, opts).ExtractErr()
195195
th.AssertEquals(t, err, io.EOF)
196196
}
197+
198+
func TestGetAdvertisedRoutes(t *testing.T) {
199+
th.SetupHTTP()
200+
defer th.TeardownHTTP()
201+
202+
bgpSpeakerID := "ab01ade1-ae62-43c9-8a1f-3c24225b96d8"
203+
th.Mux.HandleFunc("/v2.0/bgp-speakers/"+bgpSpeakerID+"/get_advertised_routes", func(w http.ResponseWriter, r *http.Request) {
204+
th.TestMethod(t, r, "GET")
205+
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
206+
w.Header().Add("Content-Type", "application/json")
207+
w.WriteHeader(http.StatusOK)
208+
fmt.Fprintf(w, GetAdvertisedRoutesResult)
209+
})
210+
211+
count := 0
212+
speakers.GetAdvertisedRoutes(fake.ServiceClient(), bgpSpeakerID).EachPage(
213+
func(page pagination.Page) (bool, error) {
214+
count++
215+
actual, err := speakers.ExtractAdvertisedRoutes(page)
216+
217+
if err != nil {
218+
t.Errorf("Failed to extract Advertised route: %v", err)
219+
return false, nil
220+
}
221+
222+
expected := []speakers.AdvertisedRoute{
223+
speakers.AdvertisedRoute{NextHop: "172.17.128.212", Destination: "172.17.129.192/27"},
224+
speakers.AdvertisedRoute{NextHop: "172.17.128.218", Destination: "172.17.129.0/27"},
225+
speakers.AdvertisedRoute{NextHop: "172.17.128.231", Destination: "172.17.129.160/27"},
226+
}
227+
th.CheckDeepEquals(t, count, 1)
228+
th.CheckDeepEquals(t, expected, actual)
229+
return true, nil
230+
})
231+
}
232+
233+
func TestAddGatewayNetwork(t *testing.T) {
234+
th.SetupHTTP()
235+
defer th.TeardownHTTP()
236+
237+
bgpSpeakerID := "ab01ade1-ae62-43c9-8a1f-3c24225b96d8"
238+
networkID := "ac13bb26-6219-49c3-a880-08847f6830b7"
239+
th.Mux.HandleFunc("/v2.0/bgp-speakers/"+bgpSpeakerID+"/add_gateway_network", func(w http.ResponseWriter, r *http.Request) {
240+
th.TestMethod(t, r, "PUT")
241+
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
242+
th.TestHeader(t, r, "Content-Type", "application/json")
243+
th.TestHeader(t, r, "Accept", "application/json")
244+
th.TestJSONRequest(t, r, AddRemoveGatewayNetworkJSON)
245+
246+
w.Header().Add("Content-Type", "application/json")
247+
w.WriteHeader(http.StatusOK)
248+
fmt.Fprintf(w, AddRemoveGatewayNetworkJSON)
249+
})
250+
251+
opts := speakers.AddGatewayNetworkOpts{NetworkID: networkID}
252+
r, err := speakers.AddGatewayNetwork(fake.ServiceClient(), bgpSpeakerID, opts).Extract()
253+
th.AssertNoErr(t, err)
254+
th.AssertEquals(t, r.NetworkID, networkID)
255+
}
256+
257+
func TestRemoveGatewayNetwork(t *testing.T) {
258+
th.SetupHTTP()
259+
defer th.TeardownHTTP()
260+
261+
bgpSpeakerID := "ab01ade1-ae62-43c9-8a1f-3c24225b96d8"
262+
networkID := "ac13bb26-6219-49c3-a880-08847f6830b7"
263+
th.Mux.HandleFunc("/v2.0/bgp-speakers/"+bgpSpeakerID+"/remove_gateway_network", func(w http.ResponseWriter, r *http.Request) {
264+
th.TestMethod(t, r, "PUT")
265+
th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
266+
th.TestHeader(t, r, "Content-Type", "application/json")
267+
th.TestHeader(t, r, "Accept", "application/json")
268+
th.TestJSONRequest(t, r, AddRemoveGatewayNetworkJSON)
269+
270+
w.Header().Add("Content-Type", "application/json")
271+
w.WriteHeader(http.StatusOK)
272+
fmt.Fprintf(w, "")
273+
})
274+
275+
opts := speakers.RemoveGatewayNetworkOpts{NetworkID: networkID}
276+
err := speakers.RemoveGatewayNetwork(fake.ServiceClient(), bgpSpeakerID, opts).ExtractErr()
277+
th.AssertEquals(t, err, io.EOF)
278+
}

0 commit comments

Comments
 (0)