Skip to content

Commit c06a6b4

Browse files
author
Miguel Sama
authored
Add Nsxt route advertisement methods (#478)
* Add NSX-T Edge Gateway methods `NsxtEdgeGateway.GetNsxtRouteAdvertisement`, `NsxtEdgeGateway.GetNsxtRouteAdvertisementWithContext`, `NsxtEdgeGateway.UpdateNsxtRouteAdvertisement`, `NsxtEdgeGateway.UpdateNsxtRouteAdvertisementWithContext`, `NsxtEdgeGateway.DeleteNsxtRouteAdvertisement` and `NsxtEdgeGateway.DeleteNsxtRouteAdvertisementWithContext` that allows to manage NSX-T route advertisement.
1 parent 9c1cbfc commit c06a6b4

8 files changed

+229
-2
lines changed

.changes/v2.16.0/478-features.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* Add NSX-T Edge Gateway methods `NsxtEdgeGateway.GetNsxtRouteAdvertisement`, `NsxtEdgeGateway.GetNsxtRouteAdvertisementWithContext`, `NsxtEdgeGateway.UpdateNsxtRouteAdvertisement`, `NsxtEdgeGateway.UpdateNsxtRouteAdvertisementWithContext`, `NsxtEdgeGateway.DeleteNsxtRouteAdvertisement` and `NsxtEdgeGateway.DeleteNsxtRouteAdvertisementWithContext` that allows to manage NSX-T route advertisement [GH-478]

govcd/catalog_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -964,12 +964,12 @@ func (vcd *TestVCD) Test_CatalogQueryMediaList(check *C) {
964964
check.Assert(medias[0].Name, Equals, vcd.config.Media.Media)
965965
}
966966

967-
// Tests System function UploadMediaImage by checking if provided UDF type standard iso file uploaded.
967+
// Tests System function UploadMediaImage by using provided ISO file of UDF type.
968968
func (vcd *TestVCD) Test_CatalogUploadMediaImageWihUdfTypeIso(check *C) {
969969
fmt.Printf("Running: %s\n", check.TestName())
970970

971971
if vcd.config.Media.MediaUdfTypePath == "" {
972-
check.Skip("Skipping test because no UDF type iso path given")
972+
check.Skip("Skipping test because no UDF type ISO path was given")
973973
}
974974

975975
catalog, org := findCatalog(vcd, check, vcd.config.VCD.Catalog.Name)

govcd/nsxt_route_advertisement.go

+127
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/*
2+
* Copyright 2022 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
3+
*/
4+
5+
package govcd
6+
7+
import (
8+
"fmt"
9+
"github.com/vmware/go-vcloud-director/v2/types/v56"
10+
)
11+
12+
// GetNsxtRouteAdvertisementWithContext retrieves the list of subnets that will be advertised so that the Edge Gateway can route
13+
// out to the connected external network.
14+
func (egw *NsxtEdgeGateway) GetNsxtRouteAdvertisementWithContext(useTenantContext bool) (*types.RouteAdvertisement, error) {
15+
err := checkSanityNsxtEdgeGatewayRouteAdvertisement(egw)
16+
if err != nil {
17+
return nil, err
18+
}
19+
20+
endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointNsxtRouteAdvertisement
21+
22+
highestApiVersion, err := egw.client.getOpenApiHighestElevatedVersion(endpoint)
23+
if err != nil {
24+
return nil, err
25+
}
26+
27+
urlRef, err := egw.client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, egw.EdgeGateway.ID))
28+
if err != nil {
29+
return nil, err
30+
}
31+
32+
var tenantContextHeaders map[string]string
33+
if useTenantContext {
34+
tenantContext, err := egw.getTenantContext()
35+
if err != nil {
36+
return nil, err
37+
}
38+
39+
tenantContextHeaders = getTenantContextHeader(tenantContext)
40+
}
41+
42+
routeAdvertisement := &types.RouteAdvertisement{}
43+
err = egw.client.OpenApiGetItem(highestApiVersion, urlRef, nil, routeAdvertisement, tenantContextHeaders)
44+
if err != nil {
45+
return nil, err
46+
}
47+
48+
return routeAdvertisement, nil
49+
}
50+
51+
// GetNsxtRouteAdvertisement method is the same as GetNsxtRouteAdvertisementWithContext but sending TenantContext by default
52+
func (egw *NsxtEdgeGateway) GetNsxtRouteAdvertisement() (*types.RouteAdvertisement, error) {
53+
return egw.GetNsxtRouteAdvertisementWithContext(true)
54+
}
55+
56+
// UpdateNsxtRouteAdvertisementWithContext updates the list of subnets that will be advertised so that the Edge Gateway can route
57+
// out to the connected external network.
58+
func (egw *NsxtEdgeGateway) UpdateNsxtRouteAdvertisementWithContext(enable bool, subnets []string, useTenantContext bool) (*types.RouteAdvertisement, error) {
59+
err := checkSanityNsxtEdgeGatewayRouteAdvertisement(egw)
60+
if err != nil {
61+
return nil, err
62+
}
63+
64+
endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointNsxtRouteAdvertisement
65+
66+
highestApiVersion, err := egw.client.getOpenApiHighestElevatedVersion(endpoint)
67+
if err != nil {
68+
return nil, err
69+
}
70+
71+
urlRef, err := egw.client.OpenApiBuildEndpoint(fmt.Sprintf(endpoint, egw.EdgeGateway.ID))
72+
if err != nil {
73+
return nil, err
74+
}
75+
76+
var tenantContextHeaders map[string]string
77+
if useTenantContext {
78+
tenantContext, err := egw.getTenantContext()
79+
if err != nil {
80+
return nil, err
81+
}
82+
83+
tenantContextHeaders = getTenantContextHeader(tenantContext)
84+
}
85+
86+
routeAdvertisement := &types.RouteAdvertisement{
87+
Enable: enable,
88+
Subnets: subnets,
89+
}
90+
91+
err = egw.client.OpenApiPutItem(highestApiVersion, urlRef, nil, routeAdvertisement, nil, tenantContextHeaders)
92+
if err != nil {
93+
return nil, err
94+
}
95+
96+
return egw.GetNsxtRouteAdvertisementWithContext(useTenantContext)
97+
}
98+
99+
// UpdateNsxtRouteAdvertisement method is the same as UpdateNsxtRouteAdvertisementWithContext but sending TenantContext by default
100+
func (egw *NsxtEdgeGateway) UpdateNsxtRouteAdvertisement(enable bool, subnets []string) (*types.RouteAdvertisement, error) {
101+
return egw.UpdateNsxtRouteAdvertisementWithContext(enable, subnets, true)
102+
}
103+
104+
// DeleteNsxtRouteAdvertisementWithContext deletes the list of subnets that will be advertised.
105+
func (egw *NsxtEdgeGateway) DeleteNsxtRouteAdvertisementWithContext(useTenantContext bool) error {
106+
_, err := egw.UpdateNsxtRouteAdvertisementWithContext(false, []string{}, useTenantContext)
107+
return err
108+
}
109+
110+
// DeleteNsxtRouteAdvertisement method is the same as DeleteNsxtRouteAdvertisementWithContext but sending TenantContext by default
111+
func (egw *NsxtEdgeGateway) DeleteNsxtRouteAdvertisement() error {
112+
return egw.DeleteNsxtRouteAdvertisementWithContext(true)
113+
}
114+
115+
// checkSanityNsxtEdgeGatewayRouteAdvertisement function performs some checks to *NsxtEdgeGateway parameter and returns error
116+
// if something is wrong. It is useful with methods NsxtEdgeGateway.[Get/Update/Delete]NsxtRouteAdvertisement
117+
func checkSanityNsxtEdgeGatewayRouteAdvertisement(egw *NsxtEdgeGateway) error {
118+
if egw.EdgeGateway == nil {
119+
return fmt.Errorf("the EdgeGateway pointer is nil. Please initialize it first before using this method")
120+
}
121+
122+
if egw.EdgeGateway.ID == "" {
123+
return fmt.Errorf("the EdgeGateway ID is empty. Please initialize it first before using this method")
124+
}
125+
126+
return nil
127+
}
+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
//go:build network || nsxt || functional || openapi || ALL
2+
// +build network nsxt functional openapi ALL
3+
4+
/*
5+
* Copyright 2022 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
6+
*/
7+
8+
package govcd
9+
10+
import (
11+
"fmt"
12+
"github.com/vmware/go-vcloud-director/v2/types/v56"
13+
. "gopkg.in/check.v1"
14+
)
15+
16+
func (vcd *TestVCD) Test_NsxtEdgeRouteAdvertisement(check *C) {
17+
skipNoNsxtConfiguration(vcd, check)
18+
skipOpenApiEndpointTest(vcd, check, types.OpenApiPathVersion1_0_0+types.OpenApiEndpointNsxtRouteAdvertisement)
19+
20+
org, err := vcd.client.GetOrgByName(vcd.config.VCD.Org)
21+
check.Assert(err, IsNil)
22+
nsxtVdc, err := org.GetVDCByName(vcd.config.VCD.Nsxt.Vdc, false)
23+
check.Assert(err, IsNil)
24+
edge, err := nsxtVdc.GetNsxtEdgeGatewayByName(vcd.config.VCD.Nsxt.EdgeGateway)
25+
check.Assert(err, IsNil)
26+
27+
// Make sure we are using a dedicated Tier-0 gateway (otherwise route advertisement won't be available)
28+
edge, err = setDedicateTier0Gateway(edge, true)
29+
check.Assert(err, IsNil)
30+
check.Assert(edge, NotNil)
31+
32+
// Make sure that things get back to normal when the test is done
33+
defer setDedicateTier0Gateway(edge, false)
34+
35+
network1 := "192.168.1.0/24"
36+
network2 := "192.168.2.0/24"
37+
networksToAdvertise := []string{network1, network2} // Sample networks to advertise
38+
39+
// Test UpdateNsxtRouteAdvertisement
40+
nsxtEdgeRouteAdvertisement, err := edge.UpdateNsxtRouteAdvertisement(true, networksToAdvertise)
41+
check.Assert(err, IsNil)
42+
check.Assert(nsxtEdgeRouteAdvertisement, NotNil)
43+
check.Assert(nsxtEdgeRouteAdvertisement.Enable, Equals, true)
44+
check.Assert(len(nsxtEdgeRouteAdvertisement.Subnets), Equals, 2)
45+
check.Assert(checkNetworkInSubnetsSlice(network1, networksToAdvertise), IsNil)
46+
check.Assert(checkNetworkInSubnetsSlice(network2, networksToAdvertise), IsNil)
47+
48+
// Test DeleteNsxtRouteAdvertisement
49+
err = edge.DeleteNsxtRouteAdvertisement()
50+
check.Assert(err, IsNil)
51+
nsxtEdgeRouteAdvertisement, err = edge.GetNsxtRouteAdvertisement()
52+
check.Assert(err, IsNil)
53+
check.Assert(nsxtEdgeRouteAdvertisement, NotNil)
54+
check.Assert(nsxtEdgeRouteAdvertisement.Enable, Equals, false)
55+
check.Assert(len(nsxtEdgeRouteAdvertisement.Subnets), Equals, 0)
56+
}
57+
58+
func checkNetworkInSubnetsSlice(network string, subnets []string) error {
59+
for _, subnet := range subnets {
60+
if subnet == network {
61+
return nil
62+
}
63+
}
64+
return fmt.Errorf("network %s is not within the slice provided", network)
65+
}
66+
67+
func setDedicateTier0Gateway(edgeGateway *NsxtEdgeGateway, dedicate bool) (*NsxtEdgeGateway, error) {
68+
edgeGateway.EdgeGateway.EdgeGatewayUplinks[0].Dedicated = dedicate
69+
edgeGateway, err := edgeGateway.Update(edgeGateway.EdgeGateway)
70+
if err != nil {
71+
return nil, err
72+
}
73+
74+
return edgeGateway, nil
75+
}

govcd/openapi_endpoints.go

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ var endpointMinApiVersions = map[string]string{
4949
types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcGroupsDfwPolicies: "35.0", // VCD 10.2+
5050
types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointVdcGroupsDfwDefaultPolicies: "35.0", // VCD 10.2+
5151
types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointSecurityTags: "36.0", // VCD 10.3+
52+
types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointNsxtRouteAdvertisement: "34.0", // VCD 10.1+
5253

5354
// NSX-T ALB (Advanced/AVI Load Balancer) support was introduced in 10.2
5455
types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointAlbController: "35.0", // VCD 10.2+

govcd/tenant_context.go

+12
Original file line numberDiff line numberDiff line change
@@ -183,3 +183,15 @@ func (vdcGroup *VdcGroup) getTenantContext() (*TenantContext, error) {
183183
}
184184
return org.tenantContext()
185185
}
186+
187+
func (egw *NsxtEdgeGateway) getTenantContext() (*TenantContext, error) {
188+
if egw != nil && egw.EdgeGateway.Org != nil {
189+
if egw.EdgeGateway.Org.Name == "" || egw.EdgeGateway.Org.ID == "" {
190+
return nil, fmt.Errorf("either parent NsxtEdgeGateway Org name or ID is empty and both must be set. Org name is [%s] and Org ID is [%s]", egw.EdgeGateway.Org.Name, egw.EdgeGateway.Org.ID)
191+
}
192+
193+
return &TenantContext{OrgId: egw.EdgeGateway.Org.ID, OrgName: egw.EdgeGateway.Org.Name}, nil
194+
}
195+
196+
return nil, fmt.Errorf("NsxtEdgeGateway is not fully initialized. Please initialize it before using this method")
197+
}

types/v56/constants.go

+1
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,7 @@ const (
373373
OpenApiEndpointVdcGroupsDfwRules = "vdcGroups/%s/dfwPolicies/%s/rules"
374374
OpenApiEndpointNetworkContextProfiles = "networkContextProfiles"
375375
OpenApiEndpointSecurityTags = "securityTags"
376+
OpenApiEndpointNsxtRouteAdvertisement = "edgeGateways/%s/routing/advertisement"
376377

377378
// NSX-T ALB related endpoints
378379

types/v56/nsxt_types.go

+10
Original file line numberDiff line numberDiff line change
@@ -1244,3 +1244,13 @@ type EntitySecurityTags struct {
12441244
// Tags is the list of tags. The value is case-agnostic and will be converted to lower-case.
12451245
Tags []string `json:"tags"`
12461246
}
1247+
1248+
// RouteAdvertisement lists the subnets that will be advertised so that the Edge Gateway can route out to the
1249+
// connected external network.
1250+
type RouteAdvertisement struct {
1251+
// Enable if true, means that the subnets will be advertised.
1252+
Enable bool `json:"enable"`
1253+
// Subnets is the list of subnets that will be advertised so that the Edge Gateway can route out to the connected
1254+
// external network.
1255+
Subnets []string `json:"subnets"`
1256+
}

0 commit comments

Comments
 (0)