Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for NAT rules using proxied NSX-V API #241

Merged
merged 25 commits into from
Sep 19, 2019
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ guest properties [#235](https://github.com/vmware/go-vcloud-director/pull/235)
* Added methods `vapp.SetProductSectionList` and `vapp.GetProductSectionList` allowing to manipulate
vApp guest properties [#235](https://github.com/vmware/go-vcloud-director/pull/235)
* Added method GetStorageProfileByHref
* Added methods `CreateNsxvNatRule()`, `UpdateNsxvNatRule()`, `GetNsxvNatRuleById()`, `DeleteNsxvNatRuleById()`
vbauzys marked this conversation as resolved.
Show resolved Hide resolved
which use the proxied NSX-V API for handling NAT rules [#241](https://github.com/vmware/go-vcloud-director/pull/241)
* Added methods `GetVnicIndexFromNetworkNameType()` and `GetNetworkNameTypeFromVnicIndex()` [#241](https://github.com/vmware/go-vcloud-director/pull/241)

IMPROVEMENTS:

Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/vmware/go-vcloud-director v2.0.0+incompatible h1:3B121XZVdEOxRhv5ARswKVxXt4KznAbun8GoXNbbZWs=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
27 changes: 27 additions & 0 deletions govcd/api_vcd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ const (
TestLbAppRule = "TestLbAppRule"
TestLbVirtualServer = "TestLbVirtualServer"
TestLb = "TestLb"
TestNsxvSnatRule = "TestNsxvSnatRule"
TestNsxvDnatRule = "TestNsxvDnatRule"
)

const (
Expand Down Expand Up @@ -970,6 +972,31 @@ func (vcd *TestVCD) removeLeftoverEntities(entity CleanupEntity) {
}
return

case "nsxvNatRule":
if entity.Parent == "" {
vcd.infoCleanup("removeLeftoverEntries: [ERROR] No parent specified '%s'\n", entity.Name)
return
}

orgName, vdcName, edgeName := splitParent(entity.Parent, "|")

_, _, edge, err := getOrgVdcEdgeByNames(vcd, orgName, vdcName, edgeName)
if err != nil {
vcd.infoCleanup("removeLeftoverEntries: [ERROR] %s \n", err)
}

err = edge.DeleteNsxvNatRuleById(entity.Name)
if IsNotFound(err) {
vcd.infoCleanup(notFoundMsg, entity.EntityType, entity.Name)
return
}
if err != nil {
vcd.infoCleanup(notDeletedMsg, entity.EntityType, entity.Name, err)
}

vcd.infoCleanup(removedMsg, entity.EntityType, entity.Name, entity.CreatedBy)
return

default:
// If we reach this point, we are trying to clean up an entity that
// we aren't prepared for yet.
Expand Down
128 changes: 128 additions & 0 deletions govcd/edgegateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -1167,3 +1167,131 @@ func validateUpdateLBGeneralParams(logLevel string) error {

return nil
}

// getVnics retrieves a structure of type EdgeGatewayVnics which contains network interfaces
// available in Edge Gateway
func (egw *EdgeGateway) getVnics() (*types.EdgeGatewayVnics, error) {
if !egw.HasAdvancedNetworking() {
return nil, fmt.Errorf("only advanced edge gateway supports vNics")
}

httpPath, err := egw.buildProxiedEdgeEndpointURL(types.EdgeVnicConfig)
if err != nil {
return nil, fmt.Errorf("could not get Edge Gateway API endpoint: %s", err)
}

vnicConfig := &types.EdgeGatewayVnics{}
_, err = egw.client.ExecuteRequest(httpPath, http.MethodGet, types.AnyXMLMime,
"unable to edge gateway vnic configuration: %s", nil, vnicConfig)

if err != nil {
return nil, err
}

return vnicConfig, nil
}

// GetVnicIndexFromNetworkNameType returns *int of vNic index for specified network name and network type
// networkType one of: 'internal', 'uplink', 'trunk', 'subinterface'
// networkName cannot be empty
func (egw *EdgeGateway) GetVnicIndexFromNetworkNameType(networkName, networkType string) (*int, error) {
lvirbalas marked this conversation as resolved.
Show resolved Hide resolved
vnics, err := egw.getVnics()
if err != nil {
return nil, fmt.Errorf("cannot retrieve vNic configuration: %s", err)
}
return getVnicIndexFromNetworkNameType(networkName, networkType, vnics)
}

// GetNetworkNameTypeFromVnicIndex returns network name and network type for given vNic index
// returned networkType can be one of: 'internal', 'uplink', 'trunk', 'subinterface'
func (egw *EdgeGateway) GetNetworkNameTypeFromVnicIndex(vNicIndex int) (string, string, error) {
vnics, err := egw.getVnics()
if err != nil {
return "", "", fmt.Errorf("cannot retrieve vNic configuration: %s", err)
}
return getNetworkNameTypeFromVnicIndex(vNicIndex, vnics)
}

// getVnicIndexFromNetworkNameType is wrapped and used by public function GetVnicIndexFromNetworkNameType
func getVnicIndexFromNetworkNameType(networkName, networkType string, vnics *types.EdgeGatewayVnics) (*int, error) {
if networkName == "" {
return nil, fmt.Errorf("network name cannot be empty")
}
if networkType != types.EdgeGatewayVnicTypeUplink &&
networkType != types.EdgeGatewayVnicTypeInternal &&
networkType != types.EdgeGatewayVnicTypeTrunk &&
networkType != types.EdgeGatewayVnicTypeSubinterface {
return nil, fmt.Errorf("networkType must be one of 'uplink', 'internal', 'trunk', 'subinterface'")
}

var foundIndex *int
foundCount := 0

for _, vnic := range vnics.Vnic {
// Look for matching portgroup name and network type
if networkType != types.EdgeGatewayVnicTypeSubinterface && vnic.PortgroupName == networkName && vnic.Type == networkType {
foundIndex = vnic.Index
foundCount++
}

// if looking for subinterface - check if they are defined and search for logicalSwitchName
if networkType == types.EdgeGatewayVnicTypeSubinterface && len(vnic.SubInterfaces.SubInterface) > 0 {
for _, subInterface := range vnic.SubInterfaces.SubInterface {
if subInterface.LogicalSwitchName == networkName {
foundIndex = subInterface.Index
foundCount++
}
}
}
}

if foundCount > 1 {
return nil, fmt.Errorf("more than one (%d) networks of type '%s' with name '%s' found",
foundCount, networkType, networkName)
}

if foundCount == 0 {
return nil, ErrorEntityNotFound
}

return foundIndex, nil
}

// getNetworkNameTypeFromVnicIndex is wrapped and used by public function GetNetworkNameTypeFromVnicIndex
func getNetworkNameTypeFromVnicIndex(vNicIndex int, vnics *types.EdgeGatewayVnics) (string, string, error) {
if vNicIndex < 0 {
return "", "", fmt.Errorf("vNic index cannot be negative")
}

foundCount := 0
var networkName, networkType string

for _, vnic := range vnics.Vnic {
if vnic.Index != nil && *vnic.Index == vNicIndex {
foundCount++
networkName = vnic.PortgroupName
networkType = vnic.Type
}

// Search inside "subinterface tree"
if vnic.Type == types.EdgeGatewayVnicTypeTrunk && len(vnic.SubInterfaces.SubInterface) > 0 {
for _, subInterface := range vnic.SubInterfaces.SubInterface {
if subInterface.Index != nil && *subInterface.Index == vNicIndex {
foundCount++
networkName = subInterface.LogicalSwitchName
networkType = types.EdgeGatewayVnicTypeSubinterface
}
}
}
}

if foundCount > 1 {
return "", "", fmt.Errorf("more than one networks found for vNic %d", vNicIndex)
}

if foundCount == 0 {
return "", "", ErrorEntityNotFound
}

return networkName, networkType, nil
}
24 changes: 24 additions & 0 deletions govcd/edgegateway_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -582,3 +582,27 @@ func (vcd *TestVCD) TestEdgeGateway_UpdateLBGeneralParams(check *C) {
// Validate load balancer configuration against initially cached version
testCheckLoadBalancerConfig(beforeLb, beforeLbXml, *edge, check)
}

func (vcd *TestVCD) TestEdgeGateway_GetVnics(check *C) {
if vcd.config.VCD.EdgeGateway == "" {
check.Skip("Skipping test because no edge gatway given")
}
edge, err := vcd.vdc.FindEdgeGateway(vcd.config.VCD.EdgeGateway)
check.Assert(err, IsNil)

if !edge.HasAdvancedNetworking() {
check.Skip("Skipping test because the edge gateway does not have advanced networking enabled")
}

vnics, err := edge.getVnics()
check.Assert(err, IsNil)
check.Assert(len(vnics.Vnic) > 1, Equals, true)
check.Assert(vnics.Vnic[0].Name, Equals, vcd.config.VCD.ExternalNetwork)
check.Assert(vnics.Vnic[0].PortgroupName, Equals, vcd.config.VCD.ExternalNetwork)
check.Assert(vnics.Vnic[0].AddressGroups.AddressGroup.PrimaryAddress, Equals, vcd.config.VCD.ExternalIp)
check.Assert(vnics.Vnic[0].Type, Equals, "uplink")

check.Assert(vnics.Vnic[1].Type, Equals, "internal")
check.Assert(vnics.Vnic[1].PortgroupName, Equals, vcd.config.VCD.Network.Net1)

}
Loading