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

New functionality for handling vApp network NAT #316

Merged
merged 37 commits into from
Jun 23, 2020
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
19e5916
Add new functions for vap network and firewall
vbauzys May 21, 2020
2d10f82
add change log
vbauzys May 21, 2020
9590ff2
Merge branch 'master' into vapp-fw
vbauzys May 21, 2020
36813b3
improvements
vbauzys May 21, 2020
77449ee
add comment
vbauzys May 22, 2020
82499b4
add comment
vbauzys May 22, 2020
5f6d194
Merge branch 'master' into vapp-fw
vbauzys May 22, 2020
8f3ec68
Merge branch 'master' into vapp-fw
vbauzys May 27, 2020
368dfa8
Add first implementation
vbauzys May 29, 2020
1361ebf
Improve log messages
vbauzys May 29, 2020
3cc1ef7
Add improvements
vbauzys Jun 2, 2020
46cc77a
Add improvements
vbauzys Jun 3, 2020
8f96e92
Add improvements
vbauzys Jun 3, 2020
b428f44
Merge branch 'vapp-fw' into vapp-nat
vbauzys Jun 3, 2020
7ac3fc0
Added implementation for manage vApp nat rules
vbauzys Jun 9, 2020
8510b70
Add change log
vbauzys Jun 9, 2020
c290d0c
Merge branch 'master' into vapp-nat
vbauzys Jun 10, 2020
7ffc899
Improvements. Also added new function Remove all fw ant nat rules
vbauzys Jun 10, 2020
cf38695
Fix comment
vbauzys Jun 10, 2020
75e3ea6
Improve comments
vbauzys Jun 15, 2020
2142b7e
Remove not needed code
vbauzys Jun 16, 2020
12c89e6
Merge branch 'master' into vapp-nat
vbauzys Jun 17, 2020
1344a20
fix after merge
vbauzys Jun 17, 2020
e0c9eb8
Merge branch 'master' into vapp-nat
vbauzys Jun 19, 2020
5c2a9ec
improve comment
vbauzys Jun 19, 2020
fabb7bc
add comment
vbauzys Jun 22, 2020
956b386
add improvements
vbauzys Jun 22, 2020
8c5d93c
add improvements
vbauzys Jun 22, 2020
8df5a88
improve comment
vbauzys Jun 22, 2020
1485b6c
Fix bug which override existing rules
vbauzys Jun 22, 2020
fc50d89
Improvements
vbauzys Jun 22, 2020
f0996d5
added test
vbauzys Jun 22, 2020
4ca2be9
removed commented code
vbauzys Jun 23, 2020
784361a
add comment
vbauzys Jun 23, 2020
d0eb286
improve comment
vbauzys Jun 23, 2020
ba5c990
improve comment
vbauzys Jun 23, 2020
54a3424
Merge branch 'master' into vapp-nat
vbauzys Jun 23, 2020
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
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
* Add configuration option `WithSamlAdfs` to `NewVCDClient()` to support SAML authentication using
Active Directory Federations Services (ADFS) as IdP using WS-TRUST auth endpoint
"/adfs/services/trust/13/usernamemixed"
[#304](https://github.com/vmware/go-vcloud-director/pull/304)

[#304](https://github.com/vmware/go-vcloud-director/pull/304)
* Added methods `vapp.UpdateNetworkFirewallRules`, `vapp.UpdateNetworkFirewallRulesAsync`, `vapp.GetVappNetworkById`, `vapp.GetVappNetworkByName` and `vapp.GetVappNetworkByNameOrId` [#308](https://github.com/vmware/go-vcloud-director/pull/308)
* Added methods `vapp.UpdateNetworkNatRulesAsync`, `vapp.UpdateNetworkNatRulesAsync` [#316](https://github.com/vmware/go-vcloud-director/pull/316)
Didainius marked this conversation as resolved.
Show resolved Hide resolved

## 2.7.0 (April 10,2020)

Expand Down
5 changes: 5 additions & 0 deletions govcd/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -603,3 +603,8 @@ func takeBoolPointer(value bool) *bool {
func takeIntAddress(x int) *int {
return &x
}

// takeStringPointer is a helper that returns the address of an `string`
dataclouder marked this conversation as resolved.
Show resolved Hide resolved
func takeStringPointer(x string) *string {
return &x
}
16 changes: 9 additions & 7 deletions govcd/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func (vcd *TestVCD) createAngGetResourcesForVmCreation(check *C, vmName string)

// spawnVM spawns VMs in provided vApp from template and also applies customization script to
// spawn a Python 3 HTTP server
func spawnVM(name string, vdc Vdc, vapp VApp, net types.NetworkConnectionSection, vAppTemplate VAppTemplate, check *C, skipCustomization bool) (VM, error) {
func spawnVM(name string, vdc Vdc, vapp VApp, net types.NetworkConnectionSection, vAppTemplate VAppTemplate, check *C, skipCustomization, powerOn bool) (VM, error) {
fmt.Printf("# Spawning VM '%s'", name)
task, err := vapp.AddNewVM(name, vAppTemplate, &net, true)
check.Assert(err, IsNil)
Expand Down Expand Up @@ -115,12 +115,14 @@ func spawnVM(name string, vdc Vdc, vapp VApp, net types.NetworkConnectionSection
fmt.Printf(". Done\n")
}

fmt.Printf("# Powering on VM '%s'", name)
task, err = vm.PowerOn()
check.Assert(err, IsNil)
err = task.WaitTaskCompletion()
check.Assert(err, IsNil)
fmt.Printf(". Done\n")
if powerOn {
fmt.Printf("# Powering on VM '%s'", name)
task, err = vm.PowerOn()
check.Assert(err, IsNil)
err = task.WaitTaskCompletion()
check.Assert(err, IsNil)
fmt.Printf(". Done\n")
}

return *vm, nil
}
Expand Down
8 changes: 4 additions & 4 deletions govcd/edgegateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,7 @@ func (egw *EdgeGateway) AddNATRuleAsync(ruleDetails NatRule) (Task, error) {
//construct new rule
natRule := &types.NatRule{
RuleType: ruleDetails.NatType,
IsEnabled: true,
IsEnabled: takeBoolPointer(true),
Description: ruleDetails.Description,
GatewayNatRule: &types.GatewayNatRule{
Interface: &types.Reference{
Expand Down Expand Up @@ -632,7 +632,7 @@ func (egw *EdgeGateway) AddNATPortMappingWithUplink(network *types.OrgVDCNetwork
//add rule
natRule := &types.NatRule{
RuleType: natType,
IsEnabled: true,
IsEnabled: takeBoolPointer(true),
GatewayNatRule: &types.GatewayNatRule{
Interface: &types.Reference{
HREF: uplinkRef,
Expand Down Expand Up @@ -866,7 +866,7 @@ func (egw *EdgeGateway) Create1to1Mapping(internal, external, description string
snat := &types.NatRule{
Description: description,
RuleType: "SNAT",
IsEnabled: true,
IsEnabled: takeBoolPointer(true),
GatewayNatRule: &types.GatewayNatRule{
Interface: &types.Reference{
HREF: uplinkif,
Expand All @@ -885,7 +885,7 @@ func (egw *EdgeGateway) Create1to1Mapping(internal, external, description string
dnat := &types.NatRule{
Description: description,
RuleType: "DNAT",
IsEnabled: true,
IsEnabled: takeBoolPointer(true),
GatewayNatRule: &types.GatewayNatRule{
Interface: &types.Reference{
HREF: uplinkif,
Expand Down
4 changes: 2 additions & 2 deletions govcd/lb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ func (vcd *TestVCD) Test_LB(check *C) {
vdc, edge, vappTemplate, vapp, desiredNetConfig, err := vcd.createAngGetResourcesForVmCreation(check, TestLb)
check.Assert(err, IsNil)

vm1, err := spawnVM("FirstNode", *vdc, *vapp, desiredNetConfig, vappTemplate, check, false)
vm1, err := spawnVM("FirstNode", *vdc, *vapp, desiredNetConfig, vappTemplate, check, false, true)
check.Assert(err, IsNil)
vm2, err := spawnVM("SecondNode", *vdc, *vapp, desiredNetConfig, vappTemplate, check, false)
vm2, err := spawnVM("SecondNode", *vdc, *vapp, desiredNetConfig, vappTemplate, check, false, true)
check.Assert(err, IsNil)

// Get IPs alocated to the VMs
Expand Down
10 changes: 7 additions & 3 deletions govcd/vapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,9 +235,13 @@ func (vapp *VApp) RemoveVM(vm VM) error {
if vapp.VApp.Tasks != nil {
for _, taskItem := range vapp.VApp.Tasks.Task {
task.Task = taskItem
err := task.WaitTaskCompletion()
if err != nil {
return fmt.Errorf("error performing task: %s", err)
// Leftover tasks may have unhandled errors that can be dismissed at this stage
// we complete any incomplete tasks at this stage, to finish the refresh.
if task.Task.Status != "error" && task.Task.Status != "success" {
err := task.WaitTaskCompletion()
if err != nil {
return fmt.Errorf("error performing task: %s", err)
}
}
}
}
Expand Down
194 changes: 194 additions & 0 deletions govcd/vapp_network.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
/*
* Copyright 2020 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
*/

package govcd

import (
"fmt"
"github.com/vmware/go-vcloud-director/v2/types/v56"
"github.com/vmware/go-vcloud-director/v2/util"
"net/http"
)

// UpdateNetworkFirewallRules updates vApp networks firewall rules. It will overwrite existing ones as there is
// no 100 % way identify them separately.
dataclouder marked this conversation as resolved.
Show resolved Hide resolved
// Returns pointer to types.VAppNetwork or error
func (vapp *VApp) UpdateNetworkFirewallRules(networkId string, firewallRules []*types.FirewallRule, defaultAction string, logDefaultAction bool) (*types.VAppNetwork, error) {
task, err := vapp.UpdateNetworkFirewallRulesAsync(networkId, firewallRules, defaultAction, logDefaultAction)
if err != nil {
return nil, err
}
err = task.WaitTaskCompletion()
if err != nil {
return nil, fmt.Errorf("%s", combinedTaskErrorMessage(task.Task, err))
}

return vapp.GetVappNetworkById(networkId, false)
}

// UpdateNetworkFirewallRulesAsync asynchronously updates vApp networks firewall rules. It will overwrite existing ones
// as there is no 100 % way identify them separately.
dataclouder marked this conversation as resolved.
Show resolved Hide resolved
// Returns task or error
func (vapp *VApp) UpdateNetworkFirewallRulesAsync(networkId string, firewallRules []*types.FirewallRule, defaultAction string, logDefaultAction bool) (Task, error) {
util.Logger.Printf("[TRACE] UpdateNetworkFirewallRulesAsync with values: id: %s and firewallServiceConfiguration: %#v", networkId, firewallRules)
uuid := extractUuid(networkId)
networkToUpdate, err := vapp.GetVappNetworkById(uuid, true)
if err != nil {
return Task{}, err
}

if networkToUpdate.Configuration.Features == nil {
networkToUpdate.Configuration.Features = &types.NetworkFeatures{}
}
networkToUpdate.Xmlns = types.XMLNamespaceVCloud

// If API didn't return Firewall service XML part, that means vApp network isn't connected to org network or not fenced.
// In other words there isn't firewall when you connected directly or isolated.
if networkToUpdate.Configuration.Features.FirewallService == nil {
return Task{}, fmt.Errorf("provided network isn't connecd to org network or isn't fenced")
}
networkToUpdate.Configuration.Features.FirewallService.LogDefaultAction = logDefaultAction
networkToUpdate.Configuration.Features.FirewallService.DefaultAction = defaultAction
networkToUpdate.Configuration.Features.FirewallService.FirewallRule = firewallRules

// here we use `PUT /network/{id}` which allow to change vApp network.
// But `GET /network/{id}` can return org VDC network or vApp network.
apiEndpoint := vapp.client.VCDHREF
apiEndpoint.Path += "/network/" + uuid

return vapp.client.ExecuteTaskRequest(apiEndpoint.String(), http.MethodPut,
types.MimeVappNetwork, "error updating vApp Network firewall rules: %s", networkToUpdate)
}

// GetVappNetworkById returns a VApp network reference if the vApp network ID matches an existing one.
// If no valid VApp network is found, it returns a nil VApp network reference and an error
func (vapp *VApp) GetVappNetworkById(id string, refresh bool) (*types.VAppNetwork, error) {
util.Logger.Printf("[TRACE] [GetVappNetworkById] getting vApp Network: %s and refresh %t", id, refresh)

if refresh {
err := vapp.Refresh()
if err != nil {
return nil, fmt.Errorf("error refreshing vapp: %s", err)
}
}

//vApp Might Not Have Any networks
if vapp.VApp.NetworkConfigSection == nil || len(vapp.VApp.NetworkConfigSection.NetworkConfig) == 0 {
return nil, ErrorEntityNotFound
}

util.Logger.Printf("[TRACE] Looking for networks: %s --- %d", id, len(vapp.VApp.NetworkConfigSection.NetworkConfig))
for _, vappNetwork := range vapp.VApp.NetworkConfigSection.NetworkConfig {
// break early for disconnected network interfaces. They don't have all information
Copy link
Contributor

Choose a reason for hiding this comment

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

should it be "empty" instead of "disconnected"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

from UI perspective they are disconected

Copy link
Contributor

Choose a reason for hiding this comment

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

I am OK with using UI names in Terraform, but in the SDK we should follow the API.

if vappNetwork.NetworkName == "none" {
Didainius marked this conversation as resolved.
Show resolved Hide resolved
continue
}
util.Logger.Printf("[TRACE] Looking at: %s", vappNetwork.Link.HREF)
if equalIds(id, vappNetwork.ID, vappNetwork.Link.HREF) {
vappNetwork := &types.VAppNetwork{}

apiEndpoint := vapp.client.VCDHREF
apiEndpoint.Path += "/network/" + extractUuid(id)

_, err := vapp.client.ExecuteRequest(apiEndpoint.String(), http.MethodGet,
types.MimeVappNetwork, "error getting vApp network: %s", nil, vappNetwork)
if err != nil {
return nil, err
}
return vappNetwork, nil
}
}
util.Logger.Printf("[TRACE] GetVappNetworkById returns not found entity")
return nil, ErrorEntityNotFound
}

// GetVappNetworkByName returns a VAppNetwork reference if the vApp network name matches an existing one.
// If no valid vApp network is found, it returns a nil VAppNetwork reference and an error
func (vapp *VApp) GetVappNetworkByName(vappNetworkName string, refresh bool) (*types.VAppNetwork, error) {
util.Logger.Printf("[TRACE] [GetVappNetworkByName] getting vApp Network: %s and refresh %t", vappNetworkName, refresh)
if refresh {
err := vapp.Refresh()
if err != nil {
return nil, fmt.Errorf("error refreshing vapp: %s", err)
}
}

//vApp Might Not Have Any networks
if vapp.VApp.NetworkConfigSection == nil || len(vapp.VApp.NetworkConfigSection.NetworkConfig) == 0 {
return nil, ErrorEntityNotFound
}

util.Logger.Printf("[TRACE] Looking for networks: %s", vappNetworkName)
for _, vappNetwork := range vapp.VApp.NetworkConfigSection.NetworkConfig {

util.Logger.Printf("[TRACE] Looking at: %s", vappNetwork.NetworkName)
if vappNetwork.NetworkName == vappNetworkName {
return vapp.GetVappNetworkById(extractUuid(vappNetwork.Link.HREF), refresh)
}

}
util.Logger.Printf("[TRACE] Couldn't find vApp network: %s", vappNetworkName)
return nil, ErrorEntityNotFound
}

// GetVappNetworkByNameOrId returns a types.VAppNetwork reference if either the vApp network name or ID matches an existing one.
// If no valid vApp network is found, it returns a nil types.VAppNetwork reference and an error
func (vapp *VApp) GetVappNetworkByNameOrId(identifier string, refresh bool) (*types.VAppNetwork, error) {
getByName := func(name string, refresh bool) (interface{}, error) { return vapp.GetVappNetworkByName(name, refresh) }
getById := func(id string, refresh bool) (interface{}, error) { return vapp.GetVappNetworkById(id, refresh) }
entity, err := getEntityByNameOrId(getByName, getById, identifier, false)
if entity == nil {
return nil, err
}
return entity.(*types.VAppNetwork), err
}

// UpdateNetworkNatRules updates vApp networks NAT rules.
// Returns pointer to types.VAppNetwork or error
func (vapp *VApp) UpdateNetworkNatRules(networkId string, natRules []*types.NatRule, natType, policy string) (*types.VAppNetwork, error) {
task, err := vapp.UpdateNetworkNatRulesAsync(networkId, natRules, natType, policy)
if err != nil {
return nil, err
}
err = task.WaitTaskCompletion()
if err != nil {
return nil, fmt.Errorf("%s", combinedTaskErrorMessage(task.Task, err))
}

return vapp.GetVappNetworkById(networkId, false)
}

// UpdateNetworkNatRulesAsync asynchronously updates vApp NAT rules.
// Returns task or error
func (vapp *VApp) UpdateNetworkNatRulesAsync(networkId string, natRules []*types.NatRule, natType, policy string) (Task, error) {
util.Logger.Printf("[TRACE] UpdateNetworkNatRulesAsync with values: id: %s and natRules: %#v", networkId, natRules)

uuid := extractUuid(networkId)
dataclouder marked this conversation as resolved.
Show resolved Hide resolved
networkToUpdate, err := vapp.GetVappNetworkById(uuid, true)
if err != nil {
return Task{}, err
}

if networkToUpdate.Configuration.Features == nil {
networkToUpdate.Configuration.Features = &types.NetworkFeatures{}
}
networkToUpdate.Xmlns = types.XMLNamespaceVCloud

if networkToUpdate.Configuration.Features.NatService == nil {
return Task{}, fmt.Errorf("provided network isn't connected to org network or isn't fenced")
}
networkToUpdate.Configuration.Features.NatService.NatType = natType
networkToUpdate.Configuration.Features.NatService.Policy = policy
networkToUpdate.Configuration.Features.NatService.NatRule = natRules
networkToUpdate.Configuration.Features.NatService.IsEnabled = true
networkToUpdate.Configuration.Features.FirewallService.IsEnabled = true
lvirbalas marked this conversation as resolved.
Show resolved Hide resolved

// here we use `PUT /network/{id}` which allow to change vApp network.
// But `GET /network/{id}` can return org VDC network or vApp network.
apiEndpoint := vapp.client.VCDHREF
apiEndpoint.Path += "/network/" + uuid

return vapp.client.ExecuteTaskRequest(apiEndpoint.String(), http.MethodPut,
types.MimeVappNetwork, "error updating vApp Network NAT rules: %s", networkToUpdate)
}
Loading