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 NSX-V Edge Gateway DHCP relay settings #271

Merged
merged 5 commits into from
Dec 9, 2019
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
* Added IP set handling functions `CreateNsxvIpSet`, `UpdateNsxvIpSet`, `GetNsxvIpSetByName`,
`GetNsxvIpSetById`, `GetNsxvIpSetByNameOrId`, `GetAllNsxvIpSets`, `DeleteNsxvIpSetById`,
`DeleteNsxvIpSetByName` [#269](https://github.com/vmware/go-vcloud-director/pull/269)
* Added `UpdateDhcpRelay`, `GetDhcpRelay` and `ResetDhcpRelay` methods for Edge Gatway DHCP relay
management [#271](https://github.com/vmware/go-vcloud-director/pull/271)

BUGS FIXED:
* Remove parentheses from filtering since they weren't treated correctly in some environment [#256]
Expand Down
22 changes: 22 additions & 0 deletions govcd/api_vcd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1002,6 +1002,28 @@ func (vcd *TestVCD) removeLeftoverEntities(entity CleanupEntity) {
vcd.infoCleanup(notDeletedMsg, entity.EntityType, entity.Name, err)
}

vcd.infoCleanup(removedMsg, entity.EntityType, entity.Name, entity.CreatedBy)
return
// Edge gateway DHCP relay settings cannot actually be "deleted". They can only be unset and this is
// what this cleanup case does.
case "dhcpRelayConfig":
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.ResetDhcpRelay()
if err != nil {
vcd.infoCleanup(notDeletedMsg, entity.EntityType, entity.Name, err)
}

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

Expand Down
77 changes: 77 additions & 0 deletions govcd/nsxv_dhcprelay.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright 2019 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
*/

package govcd

import (
"fmt"
"net/http"

"github.com/vmware/go-vcloud-director/v2/types/v56"
)

// UpdateDhcpRelay updates DHCP relay settings for a particular edge gateway and returns them. The
// feature itself enables you to leverage your existing DHCP infrastructure from within NSX without
// any interruption to the IP address management in your environment. DHCP messages are relayed from
// virtual machine(s) to the designated DHCP server(s) in the physical world. This enables IP
// addresses within NSX to continue to be in sync with IP addresses in other environments.
func (egw *EdgeGateway) UpdateDhcpRelay(dhcpRelayConfig *types.EdgeDhcpRelay) (*types.EdgeDhcpRelay, error) {
if !egw.HasAdvancedNetworking() {
return nil, fmt.Errorf("only advanced edge gateways support DHCP relay")
}

httpPath, err := egw.buildProxiedEdgeEndpointURL(types.EdgeDhcpRelayPath)
if err != nil {
return nil, fmt.Errorf("could not get Edge Gateway API endpoint: %s", err)
}
// We expect to get http.StatusNoContent or if not an error of type types.NSXError
_, err = egw.client.ExecuteRequestWithCustomError(httpPath, http.MethodPut, types.AnyXMLMime,
"error setting DHCP relay settings: %s", dhcpRelayConfig, &types.NSXError{})
if err != nil {
return nil, err
}

return egw.GetDhcpRelay()
}

// GetDhcpRelay retrieves a structure of *types.EdgeDhcpRelay with all DHCP relay settings present
// on a particular edge gateway.
func (egw *EdgeGateway) GetDhcpRelay() (*types.EdgeDhcpRelay, error) {
if !egw.HasAdvancedNetworking() {
return nil, fmt.Errorf("only advanced edge gateways support DHCP relay")
}
response := &types.EdgeDhcpRelay{}

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

// This query Edge gaateway DHCP relay using proxied NSX-V API
_, err = egw.client.ExecuteRequest(httpPath, http.MethodGet, types.AnyXMLMime,
"unable to read edge gateway DHCP relay configuration: %s", nil, response)
if err != nil {
return nil, err
}

return response, nil
}

// ResetDhcpRelay removes all configuration by sending a DELETE request for DHCP relay configuration
// endpoint
func (egw *EdgeGateway) ResetDhcpRelay() error {
if !egw.HasAdvancedNetworking() {
return fmt.Errorf("only advanced edge gateways support DHCP relay")
}

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

// Send a DELETE request to DHCP relay configuration endpoint
_, err = egw.client.ExecuteRequestWithCustomError(httpPath, http.MethodDelete, types.AnyXMLMime,
"unable to reset edge gateway DHCP relay configuration: %s", nil, &types.NSXError{})
return err
}
105 changes: 105 additions & 0 deletions govcd/nsxv_dhcprelay_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// +build nsxv functional ALL

/*
* Copyright 2019 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
*/

package govcd

import (
"github.com/vmware/go-vcloud-director/v2/types/v56"
. "gopkg.in/check.v1"
)

// Test_NsxvDhcpRelay tests out Edge gateway DHCP relay configuration settings. It does the following:
// 1. Creates an IP set to ensure it can be used in DHCP relay configuration settings.
// 2. Creates a DHCP relay configuration with multiple objects and checks. Adds a task for cleanup.
// Note. Because DHCP relay configuration is not an object, but a setting of edge gateway - there is
// nothing to delete
// 3. Resets the DHCP relay configuration and checks that it was removed
// 4. Creates another DHCP relay with different configuration (using only IP sets) and manually
// specifying IP address on edge gateway interface (vNic)
// 6. Resets the DHCP relay configuration and checks that it was removed
func (vcd *TestVCD) Test_NsxvDhcpRelay(check *C) {
if vcd.config.VCD.EdgeGateway == "" {
check.Skip("Skipping test because no edge gateway given")
}

edge, err := vcd.vdc.GetEdgeGatewayByName(vcd.config.VCD.EdgeGateway, false)
check.Assert(err, IsNil)
check.Assert(edge.EdgeGateway.Name, Equals, vcd.config.VCD.EdgeGateway)

// Setup IP set for testing purposes and add it to cleanup list
createdIpSet, err := testCreateIpSet("dhcp-relay-test", vcd.vdc)
check.Assert(err, IsNil)
parentEntity := vcd.org.Org.Name + "|" + vcd.vdc.Vdc.Name
AddToCleanupList(createdIpSet.Name, "ipSet", parentEntity, check.TestName())

// Lookup vNic index for our org network
vNicIndex, _, err := edge.GetAnyVnicIndexByNetworkName(vcd.config.VCD.Network.Net1)
check.Assert(err, IsNil)

dhcpRelayConfig := &types.EdgeDhcpRelay{
RelayServer: &types.EdgeDhcpRelayServer{
IpAddress: []string{"1.1.1.1"},
Fqdns: []string{"servergroups.domainname.com", "servergroups.otherdomainname.com"},
GroupingObjectId: []string{createdIpSet.ID},
},
RelayAgents: &types.EdgeDhcpRelayAgents{
Agents: []types.EdgeDhcpRelayAgent{
types.EdgeDhcpRelayAgent{
VnicIndex: vNicIndex,
},
},
},
}

createdRelayConfig, err := edge.UpdateDhcpRelay(dhcpRelayConfig)
check.Assert(err, IsNil)

parentEntity = vcd.org.Org.Name + "|" + vcd.vdc.Vdc.Name + "|" + vcd.config.VCD.EdgeGateway
// DHCP relay config is being prepended (added to beginning) of cleanup list because it must be
// delete first so that above created dependent IP sets can be cleaned up when their turn comes
PrependToCleanupList(check.TestName(), "dhcpRelayConfig", parentEntity, check.TestName())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment about using PrependToCleanupList instead of Add, for future reference

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added


// Cache Gateway auto-assigned address to try specifying it afterwards
vNicDefaultGateway := createdRelayConfig.RelayAgents.Agents[0].GatewayInterfaceAddress

readRelayConfig, err := edge.GetDhcpRelay()
check.Assert(err, IsNil)
check.Assert(readRelayConfig, DeepEquals, createdRelayConfig)

// Patch auto-assigned IP so that structure comparison works
dhcpRelayConfig.RelayAgents.Agents[0].GatewayInterfaceAddress = readRelayConfig.RelayAgents.Agents[0].GatewayInterfaceAddress
check.Assert(readRelayConfig.RelayServer, DeepEquals, dhcpRelayConfig.RelayServer)
check.Assert(readRelayConfig.RelayAgents, DeepEquals, dhcpRelayConfig.RelayAgents)

// Reset DHCP relay and ensure no settings are present
err = edge.ResetDhcpRelay()
check.Assert(err, IsNil)
read, err := edge.GetDhcpRelay()
check.Assert(err, IsNil)
check.Assert(read.RelayServer, IsNil)
check.Assert(read.RelayAgents, IsNil)

// Second attempt - insert gateway interface IP address during creation to prevent
// auto-assignment
dhcpRelayConfig.RelayAgents.Agents[0].GatewayInterfaceAddress = vNicDefaultGateway
// Remove IP addresses and FQDNs to only use IP sets for specifying DHCP servers addresses
dhcpRelayConfig.RelayServer.IpAddress = nil
dhcpRelayConfig.RelayServer.Fqdns = nil

createdRelayConfig2, err := edge.UpdateDhcpRelay(dhcpRelayConfig)
check.Assert(err, IsNil)
readRelayConfig2, err := edge.GetDhcpRelay()
check.Assert(err, IsNil)
check.Assert(readRelayConfig2, DeepEquals, createdRelayConfig2)

// Reset DHCP relay and ensure no settings are present
err = edge.ResetDhcpRelay()
check.Assert(err, IsNil)
read, err = edge.GetDhcpRelay()
check.Assert(err, IsNil)
check.Assert(read.RelayServer, IsNil)
check.Assert(read.RelayAgents, IsNil)
}
12 changes: 12 additions & 0 deletions govcd/nsxv_ipset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,5 +113,17 @@ func (vcd *TestVCD) Test_NsxvIpSet(check *C) {

err = vdc.DeleteNsxvIpSetByName(ipSet2.Name)
check.Assert(err, IsNil)
}

// testCreateIpSet creates an IP set with given name and returns it which is useful in other tests
// when an IP set is needed to validate inputs.
func testCreateIpSet(name string, vdc *Vdc) (*types.EdgeIpSet, error) {
ipSetConfig := &types.EdgeIpSet{
Name: name,
Description: "test-ipset-description",
IPAddresses: "192.168.200.1/24",
InheritanceAllowed: takeBoolPointer(true),
}

return vdc.CreateNsxvIpSet(ipSetConfig)
}
1 change: 1 addition & 0 deletions types/v56/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ const (
EdgeFirewallPath = "/firewall/config"
EdgeCreateFirewallPath = "/firewall/config/rules"
EdgeVnicConfig = "/vnics"
EdgeDhcpRelayPath = "/dhcp/config/relay"
LbConfigPath = "/loadbalancer/config/"
LbMonitorPath = "/loadbalancer/config/monitors/"
LbServerPoolPath = "/loadbalancer/config/pools/"
Expand Down
44 changes: 44 additions & 0 deletions types/v56/nsxv_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,3 +284,47 @@ type EdgeIpSet struct {

// EdgeIpSets is a slice of pointers to EdgeIpSet
type EdgeIpSets []*EdgeIpSet

// EdgeDhcpRelay - Dynamic Host Configuration Protocol (DHCP) relay enables you to leverage your
// existing DHCP infrastructure from within NSX without any interruption to the IP address
// management in your environment. DHCP messages are relayed from virtual machine(s) to the
// designated DHCP server(s) in the physical world. This enables IP addresses within NSX to continue
// to be in sync with IP addresses in other environments.
type EdgeDhcpRelay struct {
XMLName xml.Name `xml:"relay"`
// RelayServer specifies external relay server(s) to which DHCP messages are to be relayed to.
// The relay server can be an IP set, IP address block, domain, or a combination of all of
// these. Messages are relayed to each listed DHCP server.
RelayServer *EdgeDhcpRelayServer `xml:"relayServer"`
// EdgeDhcRelayAgents specifies a list of edge gateway interfaces (vNics) from which DHCP
// messages are to be relayed to the external DHCP relay server(s) with optional gateway
// interface addresses.
RelayAgents *EdgeDhcpRelayAgents `xml:"relayAgents"`
}

type EdgeDhcpRelayServer struct {
// GroupingObjectIds is a general concept in NSX which allows to pass in many types of objects
// (like VM IDs, IP set IDs, org networks, security groups) howether in this case it accepts
// only IP sets which have IDs specified as 'f9daf2da-b4f9-4921-a2f4-d77a943a381c:ipset-2' where
// first part is vDC ID and the second part is unique IP set ID
GroupingObjectId []string `xml:"groupingObjectId,omitempty"`
// IpAddresses holds a list of IP addresses for DHCP servers
IpAddress []string `xml:"ipAddress,omitempty"`
// Fqdn holds a list of FQDNs (fully qualified domain names)
Fqdns []string `xml:"fqdn,omitempty"`
}

// EdgeDhcpRelayAgent specifies which edge gateway interface (vNic) from which DHCP messages are to
// be relayed to the external DHCP relay server(s) with an optional gateway interface address.
type EdgeDhcpRelayAgent struct {
// VnicIndex must specify vNic adapter index on the edge gateway
VnicIndex *int `xml:"vnicIndex"`
// GatewayInterfaceAddress holds a gateway interface address. Optional, defaults to the vNic
// primary address.
GatewayInterfaceAddress string `xml:"giAddress,omitempty"`
}

// EdgeDhcpRelayAgents holds a slice of EdgeDhcpRelayAgent
type EdgeDhcpRelayAgents struct {
Agents []EdgeDhcpRelayAgent `xml:"relayAgent"`
}