terraform/vendor/github.com/hmrc/vmware-govcd/edgegateway.go

626 lines
17 KiB
Go

/*
* Copyright 2014 VMware, Inc. All rights reserved. Licensed under the Apache v2 License.
*/
package govcd
import (
"bytes"
"encoding/xml"
"fmt"
"log"
"net/http"
"net/url"
"os"
"regexp"
"time"
types "github.com/hmrc/vmware-govcd/types/v56"
)
type EdgeGateway struct {
EdgeGateway *types.EdgeGateway
c *Client
}
func NewEdgeGateway(c *Client) *EdgeGateway {
return &EdgeGateway{
EdgeGateway: new(types.EdgeGateway),
c: c,
}
}
func (e *EdgeGateway) AddDhcpPool(network *types.OrgVDCNetwork, dhcppool []interface{}) (Task, error) {
newedgeconfig := e.EdgeGateway.Configuration.EdgeGatewayServiceConfiguration
log.Printf("[DEBUG] EDGE GATEWAY: %#v", newedgeconfig)
log.Printf("[DEBUG] EDGE GATEWAY SERVICE: %#v", newedgeconfig.GatewayDhcpService)
newdchpservice := &types.GatewayDhcpService{}
if newedgeconfig.GatewayDhcpService == nil {
newdchpservice.IsEnabled = true
} else {
newdchpservice.IsEnabled = newedgeconfig.GatewayDhcpService.IsEnabled
for _, v := range newedgeconfig.GatewayDhcpService.Pool {
// Kludgy IF to avoid deleting DNAT rules not created by us.
// If matches, let's skip it and continue the loop
if v.Network.HREF == network.HREF {
continue
}
newdchpservice.Pool = append(newdchpservice.Pool, v)
}
}
for _, v := range dhcppool {
data := v.(map[string]interface{})
dhcprule := &types.DhcpPoolService{
IsEnabled: true,
Network: &types.Reference{
HREF: network.HREF,
Name: network.Name,
},
DefaultLeaseTime: 3600,
MaxLeaseTime: 7200,
LowIPAddress: data["start_address"].(string),
HighIPAddress: data["end_address"].(string),
}
newdchpservice.Pool = append(newdchpservice.Pool, dhcprule)
}
newRules := &types.EdgeGatewayServiceConfiguration{
Xmlns: "http://www.vmware.com/vcloud/v1.5",
GatewayDhcpService: newdchpservice,
}
output, err := xml.MarshalIndent(newRules, " ", " ")
if err != nil {
return Task{}, fmt.Errorf("error reconfiguring Edge Gateway: %s", err)
}
var resp *http.Response
for {
b := bytes.NewBufferString(xml.Header + string(output))
s, _ := url.ParseRequestURI(e.EdgeGateway.HREF)
s.Path += "/action/configureServices"
req := e.c.NewRequest(map[string]string{}, "POST", *s, b)
log.Printf("[DEBUG] POSTING TO URL: %s", s.Path)
log.Printf("[DEBUG] XML TO SEND:\n%s", b)
req.Header.Add("Content-Type", "application/vnd.vmware.admin.edgeGatewayServiceConfiguration+xml")
resp, err = checkResp(e.c.Http.Do(req))
if err != nil {
if v, _ := regexp.MatchString("is busy completing an operation.$", err.Error()); v {
time.Sleep(3 * time.Second)
continue
}
return Task{}, fmt.Errorf("error reconfiguring Edge Gateway: %s", err)
}
break
}
task := NewTask(e.c)
if err = decodeBody(resp, task.Task); err != nil {
return Task{}, fmt.Errorf("error decoding Task response: %s", err)
}
// The request was successful
return *task, nil
}
func (e *EdgeGateway) RemoveNATMapping(nattype, externalIP, internalIP, port string) (Task, error) {
// Find uplink interface
var uplink types.Reference
for _, gi := range e.EdgeGateway.Configuration.GatewayInterfaces.GatewayInterface {
if gi.InterfaceType != "uplink" {
continue
}
uplink = *gi.Network
}
newedgeconfig := e.EdgeGateway.Configuration.EdgeGatewayServiceConfiguration
// Take care of the NAT service
newnatservice := &types.NatService{}
newnatservice.IsEnabled = newedgeconfig.NatService.IsEnabled
newnatservice.NatType = newedgeconfig.NatService.NatType
newnatservice.Policy = newedgeconfig.NatService.Policy
newnatservice.ExternalIP = newedgeconfig.NatService.ExternalIP
for _, v := range newedgeconfig.NatService.NatRule {
// Kludgy IF to avoid deleting DNAT rules not created by us.
// If matches, let's skip it and continue the loop
if v.RuleType == nattype &&
v.GatewayNatRule.OriginalIP == externalIP &&
v.GatewayNatRule.OriginalPort == port &&
v.GatewayNatRule.Interface.HREF == uplink.HREF {
log.Printf("[DEBUG] REMOVING %s Rule: %#v", v.RuleType, v.GatewayNatRule)
continue
}
log.Printf("[DEBUG] KEEPING %s Rule: %#v", v.RuleType, v.GatewayNatRule)
newnatservice.NatRule = append(newnatservice.NatRule, v)
}
newedgeconfig.NatService = newnatservice
newRules := &types.EdgeGatewayServiceConfiguration{
Xmlns: "http://www.vmware.com/vcloud/v1.5",
NatService: newnatservice,
}
output, err := xml.MarshalIndent(newRules, " ", " ")
if err != nil {
return Task{}, fmt.Errorf("error reconfiguring Edge Gateway: %s", err)
}
b := bytes.NewBufferString(xml.Header + string(output))
s, _ := url.ParseRequestURI(e.EdgeGateway.HREF)
s.Path += "/action/configureServices"
req := e.c.NewRequest(map[string]string{}, "POST", *s, b)
log.Printf("[DEBUG] POSTING TO URL: %s", s.Path)
log.Printf("[DEBUG] XML TO SEND:\n%s", b)
req.Header.Add("Content-Type", "application/vnd.vmware.admin.edgeGatewayServiceConfiguration+xml")
resp, err := checkResp(e.c.Http.Do(req))
if err != nil {
log.Printf("[DEBUG] Error is: %#v", err)
return Task{}, fmt.Errorf("error reconfiguring Edge Gateway: %s", err)
}
task := NewTask(e.c)
if err = decodeBody(resp, task.Task); err != nil {
return Task{}, fmt.Errorf("error decoding Task response: %s", err)
}
// The request was successful
return *task, nil
}
func (e *EdgeGateway) AddNATMapping(nattype, externalIP, internalIP, port string) (Task, error) {
// Find uplink interface
var uplink types.Reference
for _, gi := range e.EdgeGateway.Configuration.GatewayInterfaces.GatewayInterface {
if gi.InterfaceType != "uplink" {
continue
}
uplink = *gi.Network
}
newedgeconfig := e.EdgeGateway.Configuration.EdgeGatewayServiceConfiguration
// Take care of the NAT service
newnatservice := &types.NatService{}
if newedgeconfig.NatService == nil {
newnatservice.IsEnabled = true
} else {
newnatservice.IsEnabled = newedgeconfig.NatService.IsEnabled
newnatservice.NatType = newedgeconfig.NatService.NatType
newnatservice.Policy = newedgeconfig.NatService.Policy
newnatservice.ExternalIP = newedgeconfig.NatService.ExternalIP
for _, v := range newedgeconfig.NatService.NatRule {
// Kludgy IF to avoid deleting DNAT rules not created by us.
// If matches, let's skip it and continue the loop
if v.RuleType == nattype &&
v.GatewayNatRule.OriginalIP == externalIP &&
v.GatewayNatRule.OriginalPort == port &&
v.GatewayNatRule.TranslatedIP == internalIP &&
v.GatewayNatRule.Interface.HREF == uplink.HREF {
continue
}
newnatservice.NatRule = append(newnatservice.NatRule, v)
}
}
//add rule
natRule := &types.NatRule{
RuleType: nattype,
IsEnabled: true,
GatewayNatRule: &types.GatewayNatRule{
Interface: &types.Reference{
HREF: uplink.HREF,
},
OriginalIP: externalIP,
OriginalPort: port,
TranslatedIP: internalIP,
TranslatedPort: port,
Protocol: "tcp",
},
}
newnatservice.NatRule = append(newnatservice.NatRule, natRule)
newedgeconfig.NatService = newnatservice
newRules := &types.EdgeGatewayServiceConfiguration{
Xmlns: "http://www.vmware.com/vcloud/v1.5",
NatService: newnatservice,
}
output, err := xml.MarshalIndent(newRules, " ", " ")
if err != nil {
return Task{}, fmt.Errorf("error reconfiguring Edge Gateway: %s", err)
}
b := bytes.NewBufferString(xml.Header + string(output))
s, _ := url.ParseRequestURI(e.EdgeGateway.HREF)
s.Path += "/action/configureServices"
req := e.c.NewRequest(map[string]string{}, "POST", *s, b)
log.Printf("[DEBUG] POSTING TO URL: %s", s.Path)
log.Printf("[DEBUG] XML TO SEND:\n%s", b)
req.Header.Add("Content-Type", "application/vnd.vmware.admin.edgeGatewayServiceConfiguration+xml")
resp, err := checkResp(e.c.Http.Do(req))
if err != nil {
log.Printf("[DEBUG] Error is: %#v", err)
return Task{}, fmt.Errorf("error reconfiguring Edge Gateway: %s", err)
}
task := NewTask(e.c)
if err = decodeBody(resp, task.Task); err != nil {
return Task{}, fmt.Errorf("error decoding Task response: %s", err)
}
// The request was successful
return *task, nil
}
func (e *EdgeGateway) CreateFirewallRules(defaultAction string, rules []*types.FirewallRule) (Task, error) {
err := e.Refresh()
if err != nil {
return Task{}, fmt.Errorf("error: %v\n", err)
}
newRules := &types.EdgeGatewayServiceConfiguration{
Xmlns: "http://www.vmware.com/vcloud/v1.5",
FirewallService: &types.FirewallService{
IsEnabled: true,
DefaultAction: defaultAction,
LogDefaultAction: true,
FirewallRule: rules,
},
}
output, err := xml.MarshalIndent(newRules, " ", " ")
if err != nil {
return Task{}, fmt.Errorf("error: %v\n", err)
}
var resp *http.Response
for {
b := bytes.NewBufferString(xml.Header + string(output))
s, _ := url.ParseRequestURI(e.EdgeGateway.HREF)
s.Path += "/action/configureServices"
req := e.c.NewRequest(map[string]string{}, "POST", *s, b)
log.Printf("[DEBUG] POSTING TO URL: %s", s.Path)
log.Printf("[DEBUG] XML TO SEND:\n%s", b)
req.Header.Add("Content-Type", "application/vnd.vmware.admin.edgeGatewayServiceConfiguration+xml")
resp, err = checkResp(e.c.Http.Do(req))
if err != nil {
if v, _ := regexp.MatchString("is busy completing an operation.$", err.Error()); v {
time.Sleep(3 * time.Second)
continue
}
return Task{}, fmt.Errorf("error reconfiguring Edge Gateway: %s", err)
}
break
}
task := NewTask(e.c)
if err = decodeBody(resp, task.Task); err != nil {
return Task{}, fmt.Errorf("error decoding Task response: %s", err)
}
// The request was successful
return *task, nil
}
func (e *EdgeGateway) Refresh() error {
if e.EdgeGateway == nil {
return fmt.Errorf("cannot refresh, Object is empty")
}
u, _ := url.ParseRequestURI(e.EdgeGateway.HREF)
req := e.c.NewRequest(map[string]string{}, "GET", *u, nil)
resp, err := checkResp(e.c.Http.Do(req))
if err != nil {
return fmt.Errorf("error retreiving Edge Gateway: %s", err)
}
// Empty struct before a new unmarshal, otherwise we end up with duplicate
// elements in slices.
e.EdgeGateway = &types.EdgeGateway{}
if err = decodeBody(resp, e.EdgeGateway); err != nil {
return fmt.Errorf("error decoding Edge Gateway response: %s", err)
}
// The request was successful
return nil
}
func (e *EdgeGateway) Remove1to1Mapping(internal, external string) (Task, error) {
// Refresh EdgeGateway rules
err := e.Refresh()
if err != nil {
fmt.Printf("error: %v\n", err)
}
var uplinkif string
for _, gifs := range e.EdgeGateway.Configuration.GatewayInterfaces.GatewayInterface {
if gifs.InterfaceType == "uplink" {
uplinkif = gifs.Network.HREF
}
}
newedgeconfig := e.EdgeGateway.Configuration.EdgeGatewayServiceConfiguration
// Take care of the NAT service
newnatservice := &types.NatService{}
// Copy over the NAT configuration
newnatservice.IsEnabled = newedgeconfig.NatService.IsEnabled
newnatservice.NatType = newedgeconfig.NatService.NatType
newnatservice.Policy = newedgeconfig.NatService.Policy
newnatservice.ExternalIP = newedgeconfig.NatService.ExternalIP
for k, v := range newedgeconfig.NatService.NatRule {
// Kludgy IF to avoid deleting DNAT rules not created by us.
// If matches, let's skip it and continue the loop
if v.RuleType == "DNAT" &&
v.GatewayNatRule.OriginalIP == external &&
v.GatewayNatRule.TranslatedIP == internal &&
v.GatewayNatRule.OriginalPort == "any" &&
v.GatewayNatRule.TranslatedPort == "any" &&
v.GatewayNatRule.Protocol == "any" &&
v.GatewayNatRule.Interface.HREF == uplinkif {
continue
}
// Kludgy IF to avoid deleting SNAT rules not created by us.
// If matches, let's skip it and continue the loop
if v.RuleType == "SNAT" &&
v.GatewayNatRule.OriginalIP == internal &&
v.GatewayNatRule.TranslatedIP == external &&
v.GatewayNatRule.Interface.HREF == uplinkif {
continue
}
// If doesn't match the above IFs, it's something we need to preserve,
// let's add it to the new NatService struct
newnatservice.NatRule = append(newnatservice.NatRule, newedgeconfig.NatService.NatRule[k])
}
// Fill the new NatService Section
newedgeconfig.NatService = newnatservice
// Take care of the Firewall service
newfwservice := &types.FirewallService{}
// Copy over the firewall configuration
newfwservice.IsEnabled = newedgeconfig.FirewallService.IsEnabled
newfwservice.DefaultAction = newedgeconfig.FirewallService.DefaultAction
newfwservice.LogDefaultAction = newedgeconfig.FirewallService.LogDefaultAction
for k, v := range newedgeconfig.FirewallService.FirewallRule {
// Kludgy IF to avoid deleting inbound FW rules not created by us.
// If matches, let's skip it and continue the loop
if v.Policy == "allow" &&
v.Protocols.Any == true &&
v.DestinationPortRange == "Any" &&
v.SourcePortRange == "Any" &&
v.SourceIP == "Any" &&
v.DestinationIP == external {
continue
}
// Kludgy IF to avoid deleting outbound FW rules not created by us.
// If matches, let's skip it and continue the loop
if v.Policy == "allow" &&
v.Protocols.Any == true &&
v.DestinationPortRange == "Any" &&
v.SourcePortRange == "Any" &&
v.SourceIP == internal &&
v.DestinationIP == "Any" {
continue
}
// If doesn't match the above IFs, it's something we need to preserve,
// let's add it to the new FirewallService struct
newfwservice.FirewallRule = append(newfwservice.FirewallRule, newedgeconfig.FirewallService.FirewallRule[k])
}
// Fill the new FirewallService Section
newedgeconfig.FirewallService = newfwservice
// Fix
newedgeconfig.NatService.IsEnabled = true
output, err := xml.MarshalIndent(newedgeconfig, " ", " ")
if err != nil {
fmt.Printf("error: %v\n", err)
}
debug := os.Getenv("GOVCLOUDAIR_DEBUG")
if debug == "true" {
fmt.Printf("\n\nXML DEBUG: %s\n\n", string(output))
}
b := bytes.NewBufferString(xml.Header + string(output))
s, _ := url.ParseRequestURI(e.EdgeGateway.HREF)
s.Path += "/action/configureServices"
req := e.c.NewRequest(map[string]string{}, "POST", *s, b)
req.Header.Add("Content-Type", "application/vnd.vmware.admin.edgeGatewayServiceConfiguration+xml")
resp, err := checkResp(e.c.Http.Do(req))
if err != nil {
return Task{}, fmt.Errorf("error reconfiguring Edge Gateway: %s", err)
}
task := NewTask(e.c)
if err = decodeBody(resp, task.Task); err != nil {
return Task{}, fmt.Errorf("error decoding Task response: %s", err)
}
// The request was successful
return *task, nil
}
func (e *EdgeGateway) Create1to1Mapping(internal, external, description string) (Task, error) {
// Refresh EdgeGateway rules
err := e.Refresh()
if err != nil {
fmt.Printf("error: %v\n", err)
}
var uplinkif string
for _, gifs := range e.EdgeGateway.Configuration.GatewayInterfaces.GatewayInterface {
if gifs.InterfaceType == "uplink" {
uplinkif = gifs.Network.HREF
}
}
newedgeconfig := e.EdgeGateway.Configuration.EdgeGatewayServiceConfiguration
snat := &types.NatRule{
Description: description,
RuleType: "SNAT",
IsEnabled: true,
GatewayNatRule: &types.GatewayNatRule{
Interface: &types.Reference{
HREF: uplinkif,
},
OriginalIP: internal,
TranslatedIP: external,
Protocol: "any",
},
}
newedgeconfig.NatService.NatRule = append(newedgeconfig.NatService.NatRule, snat)
dnat := &types.NatRule{
Description: description,
RuleType: "DNAT",
IsEnabled: true,
GatewayNatRule: &types.GatewayNatRule{
Interface: &types.Reference{
HREF: uplinkif,
},
OriginalIP: external,
OriginalPort: "any",
TranslatedIP: internal,
TranslatedPort: "any",
Protocol: "any",
},
}
newedgeconfig.NatService.NatRule = append(newedgeconfig.NatService.NatRule, dnat)
fwin := &types.FirewallRule{
Description: description,
IsEnabled: true,
Policy: "allow",
Protocols: &types.FirewallRuleProtocols{
Any: true,
},
DestinationPortRange: "Any",
DestinationIP: external,
SourcePortRange: "Any",
SourceIP: "Any",
EnableLogging: false,
}
newedgeconfig.FirewallService.FirewallRule = append(newedgeconfig.FirewallService.FirewallRule, fwin)
fwout := &types.FirewallRule{
Description: description,
IsEnabled: true,
Policy: "allow",
Protocols: &types.FirewallRuleProtocols{
Any: true,
},
DestinationPortRange: "Any",
DestinationIP: "Any",
SourcePortRange: "Any",
SourceIP: internal,
EnableLogging: false,
}
newedgeconfig.FirewallService.FirewallRule = append(newedgeconfig.FirewallService.FirewallRule, fwout)
output, err := xml.MarshalIndent(newedgeconfig, " ", " ")
if err != nil {
fmt.Printf("error: %v\n", err)
}
debug := os.Getenv("GOVCLOUDAIR_DEBUG")
if debug == "true" {
fmt.Printf("\n\nXML DEBUG: %s\n\n", string(output))
}
b := bytes.NewBufferString(xml.Header + string(output))
s, _ := url.ParseRequestURI(e.EdgeGateway.HREF)
s.Path += "/action/configureServices"
req := e.c.NewRequest(map[string]string{}, "POST", *s, b)
req.Header.Add("Content-Type", "application/vnd.vmware.admin.edgeGatewayServiceConfiguration+xml")
resp, err := checkResp(e.c.Http.Do(req))
if err != nil {
return Task{}, fmt.Errorf("error reconfiguring Edge Gateway: %s", err)
}
task := NewTask(e.c)
if err = decodeBody(resp, task.Task); err != nil {
return Task{}, fmt.Errorf("error decoding Task response: %s", err)
}
// The request was successful
return *task, nil
}