Merge branch 'master' into hmrc
This commit is contained in:
commit
cb90e6c037
|
@ -0,0 +1,12 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hashicorp/terraform/builtin/providers/vcd"
|
||||||
|
"github.com/hashicorp/terraform/plugin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
plugin.Serve(&plugin.ServeOpts{
|
||||||
|
ProviderFunc: vcd.Provider,
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package vcd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/opencredo/vmware-govcd"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
User string
|
||||||
|
Password string
|
||||||
|
Org string
|
||||||
|
Href string
|
||||||
|
VDC string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) Client() (*govcd.VCDClient, error) {
|
||||||
|
u, err := url.ParseRequestURI(c.Href)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Something went wrong: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
vcdclient := govcd.NewVCDClient(*u)
|
||||||
|
org, vcd, err := vcdclient.Authenticate(c.User, c.Password, c.Org, c.VDC)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Something went wrong: %s", err)
|
||||||
|
}
|
||||||
|
vcdclient.Org = org
|
||||||
|
vcdclient.OrgVdc = vcd
|
||||||
|
return vcdclient, nil
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
package vcd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Provider returns a terraform.ResourceProvider.
|
||||||
|
func Provider() terraform.ResourceProvider {
|
||||||
|
return &schema.Provider{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"user": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
DefaultFunc: schema.EnvDefaultFunc("VCD_USER", nil),
|
||||||
|
Description: "The user name for vcd API operations.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"password": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
DefaultFunc: schema.EnvDefaultFunc("VCD_PASSWORD", nil),
|
||||||
|
Description: "The user password for vcd API operations.",
|
||||||
|
},
|
||||||
|
|
||||||
|
"org": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
DefaultFunc: schema.EnvDefaultFunc("VCD_ORG", nil),
|
||||||
|
Description: "The vcd org for API operations",
|
||||||
|
},
|
||||||
|
|
||||||
|
"url": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
DefaultFunc: schema.EnvDefaultFunc("VCD_URL", nil),
|
||||||
|
Description: "The vcd url for vcd API operations.",
|
||||||
|
},
|
||||||
|
"vdc": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
DefaultFunc: schema.EnvDefaultFunc("VCD_VDC", ""),
|
||||||
|
Description: "The name of the VDC to run operations on",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
ResourcesMap: map[string]*schema.Resource{
|
||||||
|
"vcd_network": resourceVcdNetwork(),
|
||||||
|
"vcd_vapp": resourceVcdVApp(),
|
||||||
|
"vcd_firewall_rules": resourceVcdFirewallRules(),
|
||||||
|
"vcd_dnat": resourceVcdDNAT(),
|
||||||
|
"vcd_snat": resourceVcdSNAT(),
|
||||||
|
},
|
||||||
|
|
||||||
|
ConfigureFunc: providerConfigure,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func providerConfigure(d *schema.ResourceData) (interface{}, error) {
|
||||||
|
config := Config{
|
||||||
|
User: d.Get("user").(string),
|
||||||
|
Password: d.Get("password").(string),
|
||||||
|
Org: d.Get("org").(string),
|
||||||
|
Href: d.Get("url").(string),
|
||||||
|
VDC: d.Get("vdc").(string),
|
||||||
|
}
|
||||||
|
|
||||||
|
return config.Client()
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
package vcd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
)
|
||||||
|
|
||||||
|
var testAccProviders map[string]terraform.ResourceProvider
|
||||||
|
var testAccProvider *schema.Provider
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
testAccProvider = Provider().(*schema.Provider)
|
||||||
|
testAccProviders = map[string]terraform.ResourceProvider{
|
||||||
|
"vcd": testAccProvider,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProvider(t *testing.T) {
|
||||||
|
if err := Provider().(*schema.Provider).InternalValidate(); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProvider_impl(t *testing.T) {
|
||||||
|
var _ terraform.ResourceProvider = Provider()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccPreCheck(t *testing.T) {
|
||||||
|
if v := os.Getenv("VCD_USER"); v == "" {
|
||||||
|
t.Fatal("VCD_USER must be set for acceptance tests")
|
||||||
|
}
|
||||||
|
if v := os.Getenv("VCD_PASSWORD"); v == "" {
|
||||||
|
t.Fatal("VCD_PASSWORD must be set for acceptance tests")
|
||||||
|
}
|
||||||
|
if v := os.Getenv("VCD_ORG"); v == "" {
|
||||||
|
t.Fatal("VCD_ORG must be set for acceptance tests")
|
||||||
|
}
|
||||||
|
if v := os.Getenv("VCD_URL"); v == "" {
|
||||||
|
t.Fatal("VCD_URL must be set for acceptance tests")
|
||||||
|
}
|
||||||
|
if v := os.Getenv("VCD_EDGE_GATEWAY"); v == "" {
|
||||||
|
t.Fatal("VCD_EDGE_GATEWAY must be set for acceptance tests")
|
||||||
|
}
|
||||||
|
if v := os.Getenv("VCD_VDC"); v == "" {
|
||||||
|
t.Fatal("VCD_VDC must be set for acceptance tests")
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,140 @@
|
||||||
|
package vcd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
"github.com/opencredo/vmware-govcd"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceVcdDNAT() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Create: resourceVcdDNATCreate,
|
||||||
|
Update: resourceVcdDNATUpdate,
|
||||||
|
Delete: resourceVcdDNATDelete,
|
||||||
|
Read: resourceVcdDNATRead,
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"edge_gateway": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"external_ip": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"port": &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"internal_ip": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceVcdDNATCreate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
vcd_client := meta.(*govcd.VCDClient)
|
||||||
|
// Multiple VCD components need to run operations on the Edge Gateway, as
|
||||||
|
// the edge gatway will throw back an error if it is already performing an
|
||||||
|
// operation we must wait until we can aquire a lock on the client
|
||||||
|
vcd_client.Mutex.Lock()
|
||||||
|
defer vcd_client.Mutex.Unlock()
|
||||||
|
portString := getPortString(d.Get("port").(int))
|
||||||
|
|
||||||
|
edgeGateway, err := vcd_client.OrgVdc.FindEdgeGateway(d.Get("edge_gateway").(string))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Unable to find edge gateway: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creating a loop to offer further protection from the edge gateway erroring
|
||||||
|
// due to being busy eg another person is using another client so wouldn't be
|
||||||
|
// constrained by out lock. If the edge gateway reurns with a busy error, wait
|
||||||
|
// 3 seconds and then try again. Continue until a non-busy error or success
|
||||||
|
|
||||||
|
err = retryCall(4, func() error {
|
||||||
|
task, err := edgeGateway.AddNATMapping("DNAT", d.Get("external_ip").(string),
|
||||||
|
d.Get("internal_ip").(string),
|
||||||
|
portString)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error setting DNAT rules: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return task.WaitTaskCompletion()
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error completing tasks: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(d.Get("external_ip").(string) + "_" + portString)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceVcdDNATUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceVcdDNATRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
vcd_client := meta.(*govcd.VCDClient)
|
||||||
|
e, err := vcd_client.OrgVdc.FindEdgeGateway(d.Get("edge_gateway").(string))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Unable to find edge gateway: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
idSplit := strings.Split(d.Id(), "_")
|
||||||
|
var found bool
|
||||||
|
|
||||||
|
for _, r := range e.EdgeGateway.Configuration.EdgeGatewayServiceConfiguration.NatService.NatRule {
|
||||||
|
if r.RuleType == "DNAT" &&
|
||||||
|
r.GatewayNatRule.OriginalIP == idSplit[0] &&
|
||||||
|
r.GatewayNatRule.OriginalPort == idSplit[1] {
|
||||||
|
found = true
|
||||||
|
d.Set("internal_ip", r.GatewayNatRule.TranslatedIP)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
d.SetId("")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceVcdDNATDelete(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
vcd_client := meta.(*govcd.VCDClient)
|
||||||
|
// Multiple VCD components need to run operations on the Edge Gateway, as
|
||||||
|
// the edge gatway will throw back an error if it is already performing an
|
||||||
|
// operation we must wait until we can aquire a lock on the client
|
||||||
|
vcd_client.Mutex.Lock()
|
||||||
|
defer vcd_client.Mutex.Unlock()
|
||||||
|
portString := getPortString(d.Get("port").(int))
|
||||||
|
|
||||||
|
edgeGateway, err := vcd_client.OrgVdc.FindEdgeGateway(d.Get("edge_gateway").(string))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Unable to find edge gateway: %#v", err)
|
||||||
|
}
|
||||||
|
err = retryCall(4, func() error {
|
||||||
|
task, err := edgeGateway.RemoveNATMapping("DNAT", d.Get("external_ip").(string),
|
||||||
|
d.Get("internal_ip").(string),
|
||||||
|
portString)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error setting DNAT rules: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return task.WaitTaskCompletion()
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error completing tasks: %#v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,120 @@
|
||||||
|
package vcd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
"github.com/opencredo/vmware-govcd"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccVcdDNAT_Basic(t *testing.T) {
|
||||||
|
if v := os.Getenv("VCD_EXTERNAL_IP"); v == "" {
|
||||||
|
t.Skip("Environment variable VCD_EXTERNAL_IP must be set to run DNAT tests")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var e govcd.EdgeGateway
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckVcdDNATDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: fmt.Sprintf(testAccCheckVcdDnat_basic, os.Getenv("VCD_EDGE_GATWEWAY"), os.Getenv("VCD_EXTERNAL_IP")),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckVcdDNATExists("vcd_dnat.bar", &e),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"vcd_dnat.bar", "external_ip", os.Getenv("VCD_EXTERNAL_IP")),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"vcd_dnat.bar", "port", "77"),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"vcd_dnat.bar", "internal_ip", "10.10.102.60"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckVcdDNATExists(n string, gateway *govcd.EdgeGateway) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
rs, ok := s.RootModule().Resources[n]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Not found: %s", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rs.Primary.ID == "" {
|
||||||
|
return fmt.Errorf("No DNAT ID is set")
|
||||||
|
}
|
||||||
|
|
||||||
|
conn := testAccProvider.Meta().(*govcd.VCDClient)
|
||||||
|
|
||||||
|
gatewayName := rs.Primary.Attributes["edge_gateway"]
|
||||||
|
edgeGateway, err := conn.OrgVdc.FindEdgeGateway(gatewayName)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Could not find edge gateway")
|
||||||
|
}
|
||||||
|
|
||||||
|
var found bool
|
||||||
|
for _, v := range edgeGateway.EdgeGateway.Configuration.EdgeGatewayServiceConfiguration.NatService.NatRule {
|
||||||
|
if v.RuleType == "DNAT" &&
|
||||||
|
v.GatewayNatRule.OriginalIP == os.Getenv("VCD_EXTERNAL_IP") &&
|
||||||
|
v.GatewayNatRule.OriginalPort == "77" &&
|
||||||
|
v.GatewayNatRule.TranslatedIP == "10.10.102.60" {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
return fmt.Errorf("DNAT rule was not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
*gateway = edgeGateway
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckVcdDNATDestroy(s *terraform.State) error {
|
||||||
|
conn := testAccProvider.Meta().(*govcd.VCDClient)
|
||||||
|
for _, rs := range s.RootModule().Resources {
|
||||||
|
if rs.Type != "vcd_dnat" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
gatewayName := rs.Primary.Attributes["edge_gateway"]
|
||||||
|
edgeGateway, err := conn.OrgVdc.FindEdgeGateway(gatewayName)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Could not find edge gateway")
|
||||||
|
}
|
||||||
|
|
||||||
|
var found bool
|
||||||
|
for _, v := range edgeGateway.EdgeGateway.Configuration.EdgeGatewayServiceConfiguration.NatService.NatRule {
|
||||||
|
if v.RuleType == "DNAT" &&
|
||||||
|
v.GatewayNatRule.OriginalIP == os.Getenv("VCD_EXTERNAL_IP") &&
|
||||||
|
v.GatewayNatRule.OriginalPort == "77" &&
|
||||||
|
v.GatewayNatRule.TranslatedIP == "10.10.102.60" {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if found {
|
||||||
|
return fmt.Errorf("DNAT rule still exists.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const testAccCheckVcdDnat_basic = `
|
||||||
|
resource "vcd_dnat" "bar" {
|
||||||
|
edge_gateway = "%s"
|
||||||
|
external_ip = "%s"
|
||||||
|
port = 77
|
||||||
|
internal_ip = "10.10.102.60"
|
||||||
|
}
|
||||||
|
`
|
|
@ -0,0 +1,241 @@
|
||||||
|
package vcd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"github.com/hashicorp/terraform/helper/hashcode"
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
"github.com/opencredo/vmware-govcd"
|
||||||
|
types "github.com/opencredo/vmware-govcd/types/v56"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceVcdFirewallRules() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Create: resourceVcdFirewallRulesCreate,
|
||||||
|
Delete: resourceFirewallRulesDelete,
|
||||||
|
Read: resourceFirewallRulesRead,
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"edge_gateway": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"default_action": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"rule": &schema.Schema{
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"id": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"description": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"policy": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"protocol": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"destination_port": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"destination_ip": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"source_port": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"source_ip": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Set: resourceVcdNetworkFirewallRuleHash,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceVcdFirewallRulesCreate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
vcd_client := meta.(*govcd.VCDClient)
|
||||||
|
vcd_client.Mutex.Lock()
|
||||||
|
defer vcd_client.Mutex.Unlock()
|
||||||
|
|
||||||
|
edgeGateway, err := vcd_client.OrgVdc.FindEdgeGateway(d.Get("edge_gateway").(string))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Unable to find edge gateway: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = retryCall(5, func() error {
|
||||||
|
edgeGateway.Refresh()
|
||||||
|
firewallRules, _ := expandFirewallRules(d.Get("rule").(*schema.Set).List(), edgeGateway.EdgeGateway)
|
||||||
|
task, err := edgeGateway.CreateFirewallRules(d.Get("default_action").(string), firewallRules)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error setting firewall rules: %#v", err)
|
||||||
|
}
|
||||||
|
return task.WaitTaskCompletion()
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error completing tasks: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(d.Get("edge_gateway").(string))
|
||||||
|
|
||||||
|
return resourceFirewallRulesRead(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceFirewallRulesDelete(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
vcd_client := meta.(*govcd.VCDClient)
|
||||||
|
vcd_client.Mutex.Lock()
|
||||||
|
defer vcd_client.Mutex.Unlock()
|
||||||
|
|
||||||
|
edgeGateway, err := vcd_client.OrgVdc.FindEdgeGateway(d.Get("edge_gateway").(string))
|
||||||
|
|
||||||
|
firewallRules := deleteFirewallRules(d.Get("rule").(*schema.Set).List(), edgeGateway.EdgeGateway)
|
||||||
|
defaultAction := edgeGateway.EdgeGateway.Configuration.EdgeGatewayServiceConfiguration.FirewallService.DefaultAction
|
||||||
|
task, err := edgeGateway.CreateFirewallRules(defaultAction, firewallRules)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error deleting firewall rules: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = task.WaitTaskCompletion()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error completing tasks: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceFirewallRulesRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
vcd_client := meta.(*govcd.VCDClient)
|
||||||
|
|
||||||
|
edgeGateway, err := vcd_client.OrgVdc.FindEdgeGateway(d.Get("edge_gateway").(string))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error finding edge gateway: %#v", err)
|
||||||
|
}
|
||||||
|
firewallRules := *edgeGateway.EdgeGateway.Configuration.EdgeGatewayServiceConfiguration.FirewallService
|
||||||
|
d.Set("rule", resourceVcdFirewallRulesGather(firewallRules.FirewallRule, d.Get("rule").(*schema.Set).List()))
|
||||||
|
d.Set("default_action", firewallRules.DefaultAction)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteFirewallRules(configured []interface{}, gateway *types.EdgeGateway) []*types.FirewallRule {
|
||||||
|
firewallRules := gateway.Configuration.EdgeGatewayServiceConfiguration.FirewallService.FirewallRule
|
||||||
|
fwrules := make([]*types.FirewallRule, 0, len(firewallRules)-len(configured))
|
||||||
|
|
||||||
|
for _, f := range firewallRules {
|
||||||
|
keep := true
|
||||||
|
for _, r := range configured {
|
||||||
|
data := r.(map[string]interface{})
|
||||||
|
if data["id"].(string) != f.ID {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
keep = false
|
||||||
|
}
|
||||||
|
if keep {
|
||||||
|
fwrules = append(fwrules, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fwrules
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceVcdFirewallRulesGather(rules []*types.FirewallRule, configured []interface{}) []map[string]interface{} {
|
||||||
|
fwrules := make([]map[string]interface{}, 0, len(configured))
|
||||||
|
|
||||||
|
for i := len(configured) - 1; i >= 0; i-- {
|
||||||
|
data := configured[i].(map[string]interface{})
|
||||||
|
rule, err := matchFirewallRule(data, rules)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fwrules = append(fwrules, rule)
|
||||||
|
}
|
||||||
|
return fwrules
|
||||||
|
}
|
||||||
|
|
||||||
|
func matchFirewallRule(data map[string]interface{}, rules []*types.FirewallRule) (map[string]interface{}, error) {
|
||||||
|
rule := make(map[string]interface{})
|
||||||
|
for _, m := range rules {
|
||||||
|
if data["id"].(string) == "" {
|
||||||
|
if data["description"].(string) == m.Description &&
|
||||||
|
data["policy"].(string) == m.Policy &&
|
||||||
|
data["protocol"].(string) == getProtocol(*m.Protocols) &&
|
||||||
|
data["destination_port"].(string) == getPortString(m.Port) &&
|
||||||
|
strings.ToLower(data["destination_ip"].(string)) == strings.ToLower(m.DestinationIP) &&
|
||||||
|
data["source_port"].(string) == getPortString(m.SourcePort) &&
|
||||||
|
strings.ToLower(data["source_ip"].(string)) == strings.ToLower(m.SourceIP) {
|
||||||
|
rule["id"] = m.ID
|
||||||
|
rule["description"] = m.Description
|
||||||
|
rule["policy"] = m.Policy
|
||||||
|
rule["protocol"] = getProtocol(*m.Protocols)
|
||||||
|
rule["destination_port"] = getPortString(m.Port)
|
||||||
|
rule["destination_ip"] = strings.ToLower(m.DestinationIP)
|
||||||
|
rule["source_port"] = getPortString(m.SourcePort)
|
||||||
|
rule["source_ip"] = strings.ToLower(m.SourceIP)
|
||||||
|
return rule, nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if data["id"].(string) == m.ID {
|
||||||
|
rule["id"] = m.ID
|
||||||
|
rule["description"] = m.Description
|
||||||
|
rule["policy"] = m.Policy
|
||||||
|
rule["protocol"] = getProtocol(*m.Protocols)
|
||||||
|
rule["destination_port"] = getPortString(m.Port)
|
||||||
|
rule["destination_ip"] = strings.ToLower(m.DestinationIP)
|
||||||
|
rule["source_port"] = getPortString(m.SourcePort)
|
||||||
|
rule["source_ip"] = strings.ToLower(m.SourceIP)
|
||||||
|
return rule, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rule, fmt.Errorf("Unable to find rule")
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceVcdNetworkFirewallRuleHash(v interface{}) int {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
m := v.(map[string]interface{})
|
||||||
|
buf.WriteString(fmt.Sprintf("%s-",
|
||||||
|
strings.ToLower(m["description"].(string))))
|
||||||
|
buf.WriteString(fmt.Sprintf("%s-",
|
||||||
|
strings.ToLower(m["policy"].(string))))
|
||||||
|
buf.WriteString(fmt.Sprintf("%s-",
|
||||||
|
strings.ToLower(m["protocol"].(string))))
|
||||||
|
buf.WriteString(fmt.Sprintf("%s-",
|
||||||
|
strings.ToLower(m["destination_port"].(string))))
|
||||||
|
buf.WriteString(fmt.Sprintf("%s-",
|
||||||
|
strings.ToLower(m["destination_ip"].(string))))
|
||||||
|
buf.WriteString(fmt.Sprintf("%s-",
|
||||||
|
strings.ToLower(m["source_port"].(string))))
|
||||||
|
buf.WriteString(fmt.Sprintf("%s-",
|
||||||
|
strings.ToLower(m["source_ip"].(string))))
|
||||||
|
|
||||||
|
return hashcode.String(buf.String())
|
||||||
|
}
|
|
@ -0,0 +1,105 @@
|
||||||
|
package vcd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
//"regexp"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
"github.com/opencredo/vmware-govcd"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccVcdFirewallRules_basic(t *testing.T) {
|
||||||
|
|
||||||
|
var existingRules, fwRules govcd.EdgeGateway
|
||||||
|
newConfig := createFirewallRulesConfigs(&existingRules)
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: newConfig,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckVcdFirewallRulesExists("vcd_firewall_rules.bar", &fwRules),
|
||||||
|
testAccCheckVcdFirewallRulesAttributes(&fwRules, &existingRules),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckVcdFirewallRulesExists(n string, gateway *govcd.EdgeGateway) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
rs, ok := s.RootModule().Resources[n]
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Not found: %s", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rs.Primary.ID == "" {
|
||||||
|
return fmt.Errorf("No Record ID is set")
|
||||||
|
}
|
||||||
|
|
||||||
|
conn := testAccProvider.Meta().(*govcd.VCDClient)
|
||||||
|
|
||||||
|
resp, err := conn.OrgVdc.FindEdgeGateway(rs.Primary.ID)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Edge Gateway does not exist.")
|
||||||
|
}
|
||||||
|
|
||||||
|
*gateway = resp
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckVcdFirewallRulesAttributes(newRules, existingRules *govcd.EdgeGateway) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
|
||||||
|
if len(newRules.EdgeGateway.Configuration.EdgeGatewayServiceConfiguration.FirewallService.FirewallRule) != len(existingRules.EdgeGateway.Configuration.EdgeGatewayServiceConfiguration.FirewallService.FirewallRule)+1 {
|
||||||
|
return fmt.Errorf("New firewall rule not added: %d != %d",
|
||||||
|
len(newRules.EdgeGateway.Configuration.EdgeGatewayServiceConfiguration.FirewallService.FirewallRule),
|
||||||
|
len(existingRules.EdgeGateway.Configuration.EdgeGatewayServiceConfiguration.FirewallService.FirewallRule)+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createFirewallRulesConfigs(existingRules *govcd.EdgeGateway) string {
|
||||||
|
config := Config{
|
||||||
|
User: os.Getenv("VCD_USER"),
|
||||||
|
Password: os.Getenv("VCD_PASSWORD"),
|
||||||
|
Org: os.Getenv("VCD_ORG"),
|
||||||
|
Href: os.Getenv("VCD_URL"),
|
||||||
|
VDC: os.Getenv("VCD_VDC"),
|
||||||
|
}
|
||||||
|
conn, _ := config.Client()
|
||||||
|
edgeGateway, _ := conn.OrgVdc.FindEdgeGateway(os.Getenv("VCD_EDGE_GATWEWAY"))
|
||||||
|
*existingRules = edgeGateway
|
||||||
|
log.Printf("[DEBUG] Edge gateway: %#v", edgeGateway)
|
||||||
|
firewallRules := *edgeGateway.EdgeGateway.Configuration.EdgeGatewayServiceConfiguration.FirewallService
|
||||||
|
return fmt.Sprintf(testAccCheckVcdFirewallRules_add, os.Getenv("VCD_EDGE_GATEWAY"), firewallRules.DefaultAction)
|
||||||
|
}
|
||||||
|
|
||||||
|
const testAccCheckVcdFirewallRules_add = `
|
||||||
|
resource "vcd_firewall_rules" "bar" {
|
||||||
|
edge_gateway = "%s"
|
||||||
|
default_action = "%s"
|
||||||
|
|
||||||
|
rule {
|
||||||
|
description = "Test rule"
|
||||||
|
policy = "allow"
|
||||||
|
protocol = "any"
|
||||||
|
destination_port = "any"
|
||||||
|
destination_ip = "any"
|
||||||
|
source_port = "any"
|
||||||
|
source_ip = "any"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
|
@ -0,0 +1,261 @@
|
||||||
|
package vcd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"github.com/hashicorp/terraform/helper/hashcode"
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
"github.com/opencredo/vmware-govcd"
|
||||||
|
types "github.com/opencredo/vmware-govcd/types/v56"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceVcdNetwork() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Create: resourceVcdNetworkCreate,
|
||||||
|
Update: resourceVcdNetworkUpdate,
|
||||||
|
Read: resourceVcdNetworkRead,
|
||||||
|
Delete: resourceVcdNetworkDelete,
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"fence_mode": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Default: "natRouted",
|
||||||
|
},
|
||||||
|
|
||||||
|
"edge_gateway": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"netmask": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Default: "255.255.255.0",
|
||||||
|
},
|
||||||
|
|
||||||
|
"gateway": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"dns1": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Default: "8.8.8.8",
|
||||||
|
},
|
||||||
|
|
||||||
|
"dns2": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Default: "8.8.4.4",
|
||||||
|
},
|
||||||
|
|
||||||
|
"dns_suffix": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"href": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"dhcp_pool": &schema.Schema{
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"start_address": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"end_address": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Set: resourceVcdNetworkIpAddressHash,
|
||||||
|
},
|
||||||
|
"static_ip_pool": &schema.Schema{
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"start_address": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"end_address": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Set: resourceVcdNetworkIpAddressHash,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceVcdNetworkCreate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
vcd_client := meta.(*govcd.VCDClient)
|
||||||
|
log.Printf("[TRACE] CLIENT: %#v", vcd_client)
|
||||||
|
vcd_client.Mutex.Lock()
|
||||||
|
defer vcd_client.Mutex.Unlock()
|
||||||
|
|
||||||
|
edgeGateway, err := vcd_client.OrgVdc.FindEdgeGateway(d.Get("edge_gateway").(string))
|
||||||
|
|
||||||
|
ipRanges, err := expandIpRange(d.Get("static_ip_pool").(*schema.Set).List())
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("error: %v\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
newnetwork := &types.OrgVDCNetwork{
|
||||||
|
Xmlns: "http://www.vmware.com/vcloud/v1.5",
|
||||||
|
Name: d.Get("name").(string),
|
||||||
|
Configuration: &types.NetworkConfiguration{
|
||||||
|
FenceMode: d.Get("fence_mode").(string),
|
||||||
|
IPScopes: &types.IPScopes{
|
||||||
|
IPScope: types.IPScope{
|
||||||
|
IsInherited: false,
|
||||||
|
Gateway: d.Get("gateway").(string),
|
||||||
|
Netmask: d.Get("netmask").(string),
|
||||||
|
DNS1: d.Get("dns1").(string),
|
||||||
|
DNS2: d.Get("dns2").(string),
|
||||||
|
DNSSuffix: d.Get("dns_suffix").(string),
|
||||||
|
IPRanges: &ipRanges,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
BackwardCompatibilityMode: true,
|
||||||
|
},
|
||||||
|
EdgeGateway: &types.Reference{
|
||||||
|
HREF: edgeGateway.EdgeGateway.HREF,
|
||||||
|
},
|
||||||
|
IsShared: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[INFO] NETWORK: %#v", newnetwork)
|
||||||
|
|
||||||
|
err = retryCall(4, func() error {
|
||||||
|
return vcd_client.OrgVdc.CreateOrgVDCNetwork(newnetwork)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = vcd_client.OrgVdc.Refresh()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error refreshing vdc: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
network, err := vcd_client.OrgVdc.FindVDCNetwork(d.Get("name").(string))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error finding network: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if dhcp, ok := d.GetOk("dhcp_pool"); ok {
|
||||||
|
err = retryCall(4, func() error {
|
||||||
|
task, err := edgeGateway.AddDhcpPool(network.OrgVDCNetwork, dhcp.(*schema.Set).List())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error adding DHCP pool: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return task.WaitTaskCompletion()
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error completing tasks: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(d.Get("name").(string))
|
||||||
|
|
||||||
|
return resourceVcdNetworkRead(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceVcdNetworkUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
|
||||||
|
vcd_client := meta.(*govcd.VCDClient)
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] VCD Client configuration: %#v", vcd_client)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceVcdNetworkRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
vcd_client := meta.(*govcd.VCDClient)
|
||||||
|
log.Printf("[DEBUG] VCD Client configuration: %#v", vcd_client)
|
||||||
|
log.Printf("[DEBUG] VCD Client configuration: %#v", vcd_client.OrgVdc)
|
||||||
|
|
||||||
|
err := vcd_client.OrgVdc.Refresh()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error refreshing vdc: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
network, err := vcd_client.OrgVdc.FindVDCNetwork(d.Id())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error finding network: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.Set("name", network.OrgVDCNetwork.Name)
|
||||||
|
d.Set("href", network.OrgVDCNetwork.HREF)
|
||||||
|
d.Set("fence_mode", network.OrgVDCNetwork.Configuration.FenceMode)
|
||||||
|
d.Set("gateway", network.OrgVDCNetwork.Configuration.IPScopes.IPScope.Gateway)
|
||||||
|
d.Set("netmask", network.OrgVDCNetwork.Configuration.IPScopes.IPScope.Netmask)
|
||||||
|
d.Set("dns1", network.OrgVDCNetwork.Configuration.IPScopes.IPScope.DNS1)
|
||||||
|
d.Set("dns2", network.OrgVDCNetwork.Configuration.IPScopes.IPScope.DNS2)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceVcdNetworkDelete(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
vcd_client := meta.(*govcd.VCDClient)
|
||||||
|
vcd_client.Mutex.Lock()
|
||||||
|
defer vcd_client.Mutex.Unlock()
|
||||||
|
err := vcd_client.OrgVdc.Refresh()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error refreshing vdc: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
network, err := vcd_client.OrgVdc.FindVDCNetwork(d.Id())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error finding network: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = retryCall(4, func() error {
|
||||||
|
task, err := network.Delete()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error Deleting Network: %#v", err)
|
||||||
|
}
|
||||||
|
return task.WaitTaskCompletion()
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceVcdNetworkIpAddressHash(v interface{}) int {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
m := v.(map[string]interface{})
|
||||||
|
buf.WriteString(fmt.Sprintf("%s-",
|
||||||
|
strings.ToLower(m["start_address"].(string))))
|
||||||
|
buf.WriteString(fmt.Sprintf("%s-",
|
||||||
|
strings.ToLower(m["end_address"].(string))))
|
||||||
|
|
||||||
|
return hashcode.String(buf.String())
|
||||||
|
}
|
|
@ -0,0 +1,107 @@
|
||||||
|
package vcd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
"github.com/opencredo/vmware-govcd"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccVcdNetwork_Basic(t *testing.T) {
|
||||||
|
var network govcd.OrgVDCNetwork
|
||||||
|
generatedHrefRegexp := regexp.MustCompile("^https://")
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckVcdNetworkDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: fmt.Sprintf(testAccCheckVcdNetwork_basic, os.Getenv("VCD_EDGE_GATWEWAY")),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckVcdNetworkExists("vcd_network.foonet", &network),
|
||||||
|
testAccCheckVcdNetworkAttributes(&network),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"vcd_network.foonet", "name", "foonet"),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"vcd_network.foonet", "static_ip_pool.#", "1"),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"vcd_network.foonet", "gateway", "10.10.102.1"),
|
||||||
|
resource.TestMatchResourceAttr(
|
||||||
|
"vcd_network.foonet", "href", generatedHrefRegexp),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckVcdNetworkExists(n string, network *govcd.OrgVDCNetwork) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
rs, ok := s.RootModule().Resources[n]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Not found: %s", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rs.Primary.ID == "" {
|
||||||
|
return fmt.Errorf("No VAPP ID is set")
|
||||||
|
}
|
||||||
|
|
||||||
|
conn := testAccProvider.Meta().(*govcd.VCDClient)
|
||||||
|
|
||||||
|
resp, err := conn.OrgVdc.FindVDCNetwork(rs.Primary.ID)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Network does not exist.")
|
||||||
|
}
|
||||||
|
|
||||||
|
*network = resp
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckVcdNetworkDestroy(s *terraform.State) error {
|
||||||
|
conn := testAccProvider.Meta().(*govcd.VCDClient)
|
||||||
|
|
||||||
|
for _, rs := range s.RootModule().Resources {
|
||||||
|
if rs.Type != "vcd_network" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := conn.OrgVdc.FindVDCNetwork(rs.Primary.ID)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
return fmt.Errorf("Network still exists.")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckVcdNetworkAttributes(network *govcd.OrgVDCNetwork) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
|
||||||
|
if network.OrgVDCNetwork.Name != "foonet" {
|
||||||
|
return fmt.Errorf("Bad name: %s", network.OrgVDCNetwork.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const testAccCheckVcdNetwork_basic = `
|
||||||
|
resource "vcd_network" "foonet" {
|
||||||
|
name = "foonet"
|
||||||
|
edge_gateway = "%s"
|
||||||
|
gateway = "10.10.102.1"
|
||||||
|
static_ip_pool {
|
||||||
|
start_address = "10.10.102.2"
|
||||||
|
end_address = "10.10.102.254"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
|
@ -0,0 +1,126 @@
|
||||||
|
package vcd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
"github.com/opencredo/vmware-govcd"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceVcdSNAT() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Create: resourceVcdSNATCreate,
|
||||||
|
Update: resourceVcdSNATUpdate,
|
||||||
|
Delete: resourceVcdSNATDelete,
|
||||||
|
Read: resourceVcdSNATRead,
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"edge_gateway": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"external_ip": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"internal_ip": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceVcdSNATCreate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
vcd_client := meta.(*govcd.VCDClient)
|
||||||
|
// Multiple VCD components need to run operations on the Edge Gateway, as
|
||||||
|
// the edge gatway will throw back an error if it is already performing an
|
||||||
|
// operation we must wait until we can aquire a lock on the client
|
||||||
|
vcd_client.Mutex.Lock()
|
||||||
|
defer vcd_client.Mutex.Unlock()
|
||||||
|
|
||||||
|
// Creating a loop to offer further protection from the edge gateway erroring
|
||||||
|
// due to being busy eg another person is using another client so wouldn't be
|
||||||
|
// constrained by out lock. If the edge gateway reurns with a busy error, wait
|
||||||
|
// 3 seconds and then try again. Continue until a non-busy error or success
|
||||||
|
edgeGateway, err := vcd_client.OrgVdc.FindEdgeGateway(d.Get("edge_gateway").(string))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Unable to find edge gateway: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = retryCall(4, func() error {
|
||||||
|
task, err := edgeGateway.AddNATMapping("SNAT", d.Get("internal_ip").(string),
|
||||||
|
d.Get("external_ip").(string),
|
||||||
|
"any")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error setting SNAT rules: %#v", err)
|
||||||
|
}
|
||||||
|
return task.WaitTaskCompletion()
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(d.Get("internal_ip").(string))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceVcdSNATUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceVcdSNATRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
vcd_client := meta.(*govcd.VCDClient)
|
||||||
|
e, err := vcd_client.OrgVdc.FindEdgeGateway(d.Get("edge_gateway").(string))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Unable to find edge gateway: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var found bool
|
||||||
|
|
||||||
|
for _, r := range e.EdgeGateway.Configuration.EdgeGatewayServiceConfiguration.NatService.NatRule {
|
||||||
|
if r.RuleType == "SNAT" &&
|
||||||
|
r.GatewayNatRule.OriginalIP == d.Id() {
|
||||||
|
found = true
|
||||||
|
d.Set("external_ip", r.GatewayNatRule.TranslatedIP)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
d.SetId("")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceVcdSNATDelete(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
vcd_client := meta.(*govcd.VCDClient)
|
||||||
|
// Multiple VCD components need to run operations on the Edge Gateway, as
|
||||||
|
// the edge gatway will throw back an error if it is already performing an
|
||||||
|
// operation we must wait until we can aquire a lock on the client
|
||||||
|
vcd_client.Mutex.Lock()
|
||||||
|
defer vcd_client.Mutex.Unlock()
|
||||||
|
|
||||||
|
edgeGateway, err := vcd_client.OrgVdc.FindEdgeGateway(d.Get("edge_gateway").(string))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Unable to find edge gateway: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = retryCall(4, func() error {
|
||||||
|
task, err := edgeGateway.RemoveNATMapping("SNAT", d.Get("internal_ip").(string),
|
||||||
|
d.Get("external_ip").(string),
|
||||||
|
"")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error setting SNAT rules: %#v", err)
|
||||||
|
}
|
||||||
|
return task.WaitTaskCompletion()
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,119 @@
|
||||||
|
package vcd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
"github.com/opencredo/vmware-govcd"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccVcdSNAT_Basic(t *testing.T) {
|
||||||
|
if v := os.Getenv("VCD_EXTERNAL_IP"); v == "" {
|
||||||
|
t.Skip("Environment variable VCD_EXTERNAL_IP must be set to run SNAT tests")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var e govcd.EdgeGateway
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckVcdSNATDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: fmt.Sprintf(testAccCheckVcdSnat_basic, os.Getenv("VCD_EDGE_GATWEWAY"), os.Getenv("VCD_EXTERNAL_IP")),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckVcdSNATExists("vcd_snat.bar", &e),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"vcd_snat.bar", "external_ip", os.Getenv("VCD_EXTERNAL_IP")),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"vcd_snat.bar", "internal_ip", "10.10.102.0/24"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckVcdSNATExists(n string, gateway *govcd.EdgeGateway) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
rs, ok := s.RootModule().Resources[n]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Not found: %s", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
//return fmt.Errorf("Check this: %#v", rs.Primary)
|
||||||
|
|
||||||
|
if rs.Primary.ID == "" {
|
||||||
|
return fmt.Errorf("No SNAT ID is set")
|
||||||
|
}
|
||||||
|
|
||||||
|
conn := testAccProvider.Meta().(*govcd.VCDClient)
|
||||||
|
|
||||||
|
gatewayName := rs.Primary.Attributes["edge_gateway"]
|
||||||
|
edgeGateway, err := conn.OrgVdc.FindEdgeGateway(gatewayName)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Could not find edge gateway")
|
||||||
|
}
|
||||||
|
|
||||||
|
var found bool
|
||||||
|
for _, v := range edgeGateway.EdgeGateway.Configuration.EdgeGatewayServiceConfiguration.NatService.NatRule {
|
||||||
|
if v.RuleType == "SNAT" &&
|
||||||
|
v.GatewayNatRule.OriginalIP == "10.10.102.0/24" &&
|
||||||
|
v.GatewayNatRule.OriginalPort == "" &&
|
||||||
|
v.GatewayNatRule.TranslatedIP == os.Getenv("VCD_EXTERNAL_IP") {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
return fmt.Errorf("SNAT rule was not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
*gateway = edgeGateway
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckVcdSNATDestroy(s *terraform.State) error {
|
||||||
|
conn := testAccProvider.Meta().(*govcd.VCDClient)
|
||||||
|
for _, rs := range s.RootModule().Resources {
|
||||||
|
if rs.Type != "vcd_snat" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
gatewayName := rs.Primary.Attributes["edge_gateway"]
|
||||||
|
edgeGateway, err := conn.OrgVdc.FindEdgeGateway(gatewayName)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Could not find edge gateway")
|
||||||
|
}
|
||||||
|
|
||||||
|
var found bool
|
||||||
|
for _, v := range edgeGateway.EdgeGateway.Configuration.EdgeGatewayServiceConfiguration.NatService.NatRule {
|
||||||
|
if v.RuleType == "SNAT" &&
|
||||||
|
v.GatewayNatRule.OriginalIP == "10.10.102.0/24" &&
|
||||||
|
v.GatewayNatRule.OriginalPort == "" &&
|
||||||
|
v.GatewayNatRule.TranslatedIP == os.Getenv("VCD_EXTERNAL_IP") {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if found {
|
||||||
|
return fmt.Errorf("SNAT rule still exists.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const testAccCheckVcdSnat_basic = `
|
||||||
|
resource "vcd_snat" "bar" {
|
||||||
|
edge_gateway = "%s"
|
||||||
|
external_ip = "%s"
|
||||||
|
internal_ip = "10.10.102.0/24"
|
||||||
|
}
|
||||||
|
`
|
|
@ -0,0 +1,392 @@
|
||||||
|
package vcd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
"github.com/opencredo/vmware-govcd"
|
||||||
|
types "github.com/opencredo/vmware-govcd/types/v56"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceVcdVApp() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Create: resourceVcdVAppCreate,
|
||||||
|
Update: resourceVcdVAppUpdate,
|
||||||
|
Read: resourceVcdVAppRead,
|
||||||
|
Delete: resourceVcdVAppDelete,
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"template_name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"catalog_name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"network_href": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"network_name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"memory": &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"cpus": &schema.Schema{
|
||||||
|
Type: schema.TypeInt,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"ip": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"initscript": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"metadata": &schema.Schema{
|
||||||
|
Type: schema.TypeMap,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"href": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"power_on": &schema.Schema{
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
Default: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceVcdVAppCreate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
vcd_client := meta.(*govcd.VCDClient)
|
||||||
|
|
||||||
|
catalog, err := vcd_client.Org.FindCatalog(d.Get("catalog_name").(string))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error finding catalog: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
catalogitem, err := catalog.FindCatalogItem(d.Get("template_name").(string))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error finding catelog item: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
vapptemplate, err := catalogitem.GetVAppTemplate()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error finding VAppTemplate: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] VAppTemplate: %#v", vapptemplate)
|
||||||
|
var networkHref string
|
||||||
|
net, err := vcd_client.OrgVdc.FindVDCNetwork(d.Get("network_name").(string))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error finding OrgVCD Network: %#v", err)
|
||||||
|
}
|
||||||
|
if attr, ok := d.GetOk("network_href"); ok {
|
||||||
|
networkHref = attr.(string)
|
||||||
|
} else {
|
||||||
|
networkHref = net.OrgVDCNetwork.HREF
|
||||||
|
}
|
||||||
|
// vapptemplate := govcd.NewVAppTemplate(&vcd_client.Client)
|
||||||
|
//
|
||||||
|
createvapp := &types.InstantiateVAppTemplateParams{
|
||||||
|
Ovf: "http://schemas.dmtf.org/ovf/envelope/1",
|
||||||
|
Xmlns: "http://www.vmware.com/vcloud/v1.5",
|
||||||
|
Name: d.Get("name").(string),
|
||||||
|
InstantiationParams: &types.InstantiationParams{
|
||||||
|
NetworkConfigSection: &types.NetworkConfigSection{
|
||||||
|
Info: "Configuration parameters for logical networks",
|
||||||
|
NetworkConfig: &types.VAppNetworkConfiguration{
|
||||||
|
NetworkName: d.Get("network_name").(string),
|
||||||
|
Configuration: &types.NetworkConfiguration{
|
||||||
|
ParentNetwork: &types.Reference{
|
||||||
|
HREF: networkHref,
|
||||||
|
},
|
||||||
|
FenceMode: "bridged",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Source: &types.Reference{
|
||||||
|
HREF: vapptemplate.VAppTemplate.HREF,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err = retryCall(4, func() error {
|
||||||
|
e := vcd_client.OrgVdc.InstantiateVAppTemplate(createvapp)
|
||||||
|
|
||||||
|
if e != nil {
|
||||||
|
return fmt.Errorf("Error: %#v", e)
|
||||||
|
}
|
||||||
|
|
||||||
|
e = vcd_client.OrgVdc.Refresh()
|
||||||
|
if e != nil {
|
||||||
|
return fmt.Errorf("Error: %#v", e)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// err = resource.Retry(4*time.Minute, func() error {
|
||||||
|
// err = vcd_client.OrgVdc.InstantiateVAppTemplate(createvapp)
|
||||||
|
//
|
||||||
|
// if err != nil {
|
||||||
|
// return fmt.Errorf("Error: %#v", err)
|
||||||
|
// }
|
||||||
|
// return nil
|
||||||
|
// })
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
|
||||||
|
vapp, err := vcd_client.OrgVdc.FindVAppByName(d.Get("name").(string))
|
||||||
|
|
||||||
|
err = retryCall(4, func() error {
|
||||||
|
task, err := vapp.ChangeMemorySize(d.Get("memory").(int))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error changing memory size: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return task.WaitTaskCompletion()
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = retryCall(4, func() error {
|
||||||
|
task, err := vapp.ChangeCPUcount(d.Get("cpus").(int))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error changing cpu count: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return task.WaitTaskCompletion()
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error completing task: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = retryCall(4, func() error {
|
||||||
|
task, err := vapp.ChangeVMName(d.Get("name").(string))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error with vm name change: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return task.WaitTaskCompletion()
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error changing vmname: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = retryCall(4, func() error {
|
||||||
|
task, err := vapp.ChangeNetworkConfig(d.Get("network_name").(string), d.Get("ip").(string))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error with Networking change: %#v", err)
|
||||||
|
}
|
||||||
|
return task.WaitTaskCompletion()
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error changing network: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = retryCall(4, func() error {
|
||||||
|
metadata := d.Get("metadata").(map[string]interface{})
|
||||||
|
for k, v := range metadata {
|
||||||
|
task, err := vapp.AddMetadata(k, v.(string))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error adding metadata: %#v", err)
|
||||||
|
}
|
||||||
|
err = task.WaitTaskCompletion()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error completing tasks: %#v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error adding metadata: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if initscript, ok := d.GetOk("initscript"); ok {
|
||||||
|
err = retryCall(4, func() error {
|
||||||
|
task, err := vapp.RunCustomizationScript(d.Get("name").(string), initscript.(string))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error with setting init script: %#v", err)
|
||||||
|
}
|
||||||
|
return task.WaitTaskCompletion()
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error completing tasks: %#v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.Get("power_on").(bool) {
|
||||||
|
err = retryCall(4, func() error {
|
||||||
|
task, err := vapp.PowerOn()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error Powering Up: %#v", err)
|
||||||
|
}
|
||||||
|
return task.WaitTaskCompletion()
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error completing tasks: %#v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(d.Get("name").(string))
|
||||||
|
|
||||||
|
return resourceVcdVAppRead(d, meta)
|
||||||
|
//return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceVcdVAppUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
vcd_client := meta.(*govcd.VCDClient)
|
||||||
|
vapp, err := vcd_client.OrgVdc.FindVAppByName(d.Id())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error finding VApp: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
status, err := vapp.GetStatus()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error getting VApp status: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChange("metadata") {
|
||||||
|
oraw, nraw := d.GetChange("metadata")
|
||||||
|
metadata := oraw.(map[string]interface{})
|
||||||
|
for k, _ := range metadata {
|
||||||
|
task, err := vapp.DeleteMetadata(k)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error deleting metadata: %#v", err)
|
||||||
|
}
|
||||||
|
err = task.WaitTaskCompletion()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error completing tasks: %#v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
metadata = nraw.(map[string]interface{})
|
||||||
|
for k, v := range metadata {
|
||||||
|
task, err := vapp.AddMetadata(k, v.(string))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error adding metadata: %#v", err)
|
||||||
|
}
|
||||||
|
err = task.WaitTaskCompletion()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error completing tasks: %#v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChange("memory") || d.HasChange("cpus") || d.HasChange("power_on") {
|
||||||
|
if status != "POWERED_OFF" {
|
||||||
|
task, err := vapp.PowerOff()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error Powering Off: %#v", err)
|
||||||
|
}
|
||||||
|
err = task.WaitTaskCompletion()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error completing tasks: %#v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChange("memory") {
|
||||||
|
task, err := vapp.ChangeMemorySize(d.Get("memory").(int))
|
||||||
|
err = task.WaitTaskCompletion()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error changing memory size: %#v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChange("cpus") {
|
||||||
|
task, err := vapp.ChangeCPUcount(d.Get("cpus").(int))
|
||||||
|
err = task.WaitTaskCompletion()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error changing cpu count: %#v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.Get("power_on").(bool) {
|
||||||
|
task, err := vapp.PowerOn()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error Powering Up: %#v", err)
|
||||||
|
}
|
||||||
|
err = task.WaitTaskCompletion()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error completing tasks: %#v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return resourceVcdVAppRead(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceVcdVAppRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
vcd_client := meta.(*govcd.VCDClient)
|
||||||
|
|
||||||
|
err := vcd_client.OrgVdc.Refresh()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error refreshing vdc: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
vapp, err := vcd_client.OrgVdc.FindVAppByName(d.Id())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error finding vapp: %#v", err)
|
||||||
|
}
|
||||||
|
d.Set("ip", vapp.VApp.Children.VM[0].NetworkConnectionSection.NetworkConnection.IPAddress)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceVcdVAppDelete(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
vcd_client := meta.(*govcd.VCDClient)
|
||||||
|
vapp, err := vcd_client.OrgVdc.FindVAppByName(d.Id())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error finding vdc: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
task, err := vapp.Undeploy()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error Powering Off: %#v", err)
|
||||||
|
}
|
||||||
|
err = task.WaitTaskCompletion()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error completing tasks: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
task, err = vapp.Delete()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error Powering Off: %#v", err)
|
||||||
|
}
|
||||||
|
err = task.WaitTaskCompletion()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error completing tasks: %#v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,180 @@
|
||||||
|
package vcd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
"github.com/opencredo/vmware-govcd"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccVcdVApp_PowerOff(t *testing.T) {
|
||||||
|
var vapp govcd.VApp
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckVcdVAppDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: fmt.Sprintf(testAccCheckVcdVApp_basic, os.Getenv("VCD_EDGE_GATWEWAY")),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckVcdVAppExists("vcd_vapp.foobar", &vapp),
|
||||||
|
testAccCheckVcdVAppAttributes(&vapp),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"vcd_vapp.foobar", "name", "foobar"),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"vcd_vapp.foobar", "ip", "10.10.102.160"),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"vcd_vapp.foobar", "power_on", "true"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccCheckVcdVApp_powerOff,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckVcdVAppExists("vcd_vapp.foobar", &vapp),
|
||||||
|
testAccCheckVcdVAppAttributes_off(&vapp),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"vcd_vapp.foobar", "name", "foobar"),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"vcd_vapp.foobar", "ip", "10.10.102.160"),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"vcd_vapp.foobar", "power_on", "false"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckVcdVAppExists(n string, vapp *govcd.VApp) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
rs, ok := s.RootModule().Resources[n]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Not found: %s", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rs.Primary.ID == "" {
|
||||||
|
return fmt.Errorf("No VAPP ID is set")
|
||||||
|
}
|
||||||
|
|
||||||
|
conn := testAccProvider.Meta().(*govcd.VCDClient)
|
||||||
|
|
||||||
|
resp, err := conn.OrgVdc.FindVAppByName(rs.Primary.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*vapp = resp
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckVcdVAppDestroy(s *terraform.State) error {
|
||||||
|
conn := testAccProvider.Meta().(*govcd.VCDClient)
|
||||||
|
|
||||||
|
for _, rs := range s.RootModule().Resources {
|
||||||
|
if rs.Type != "vcd_vapp" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := conn.OrgVdc.FindVAppByName(rs.Primary.ID)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
return fmt.Errorf("VPCs still exist.")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckVcdVAppAttributes(vapp *govcd.VApp) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
|
||||||
|
if vapp.VApp.Name != "foobar" {
|
||||||
|
return fmt.Errorf("Bad name: %s", vapp.VApp.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if vapp.VApp.Name != vapp.VApp.Children.VM[0].Name {
|
||||||
|
return fmt.Errorf("VApp and VM names do not match. %s != %s",
|
||||||
|
vapp.VApp.Name, vapp.VApp.Children.VM[0].Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
status, _ := vapp.GetStatus()
|
||||||
|
if status != "POWERED_ON" {
|
||||||
|
return fmt.Errorf("VApp is not powered on")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckVcdVAppAttributes_off(vapp *govcd.VApp) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
|
||||||
|
if vapp.VApp.Name != "foobar" {
|
||||||
|
return fmt.Errorf("Bad name: %s", vapp.VApp.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if vapp.VApp.Name != vapp.VApp.Children.VM[0].Name {
|
||||||
|
return fmt.Errorf("VApp and VM names do not match. %s != %s",
|
||||||
|
vapp.VApp.Name, vapp.VApp.Children.VM[0].Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
status, _ := vapp.GetStatus()
|
||||||
|
if status != "POWERED_OFF" {
|
||||||
|
return fmt.Errorf("VApp is still powered on")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const testAccCheckVcdVApp_basic = `
|
||||||
|
resource "vcd_network" "foonet" {
|
||||||
|
name = "foonet"
|
||||||
|
edge_gateway = "%s"
|
||||||
|
gateway = "10.10.102.1"
|
||||||
|
static_ip_pool {
|
||||||
|
start_address = "10.10.102.2"
|
||||||
|
end_address = "10.10.102.254"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "vcd_vapp" "foobar" {
|
||||||
|
name = "foobar"
|
||||||
|
template_name = "base-centos-7.0-x86_64_v-0.1_b-74"
|
||||||
|
catalog_name = "NubesLab"
|
||||||
|
network_name = "${vcd_network.foonet.name}"
|
||||||
|
memory = 1024
|
||||||
|
cpus = 1
|
||||||
|
ip = "10.10.102.160"
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const testAccCheckVcdVApp_powerOff = `
|
||||||
|
resource "vcd_network" "foonet" {
|
||||||
|
name = "foonet"
|
||||||
|
edge_gateway = "%s"
|
||||||
|
gateway = "10.10.102.1"
|
||||||
|
static_ip_pool {
|
||||||
|
start_address = "10.10.102.2"
|
||||||
|
end_address = "10.10.102.254"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "vcd_vapp" "foobar" {
|
||||||
|
name = "foobar"
|
||||||
|
template_name = "base-centos-7.0-x86_64_v-0.1_b-74"
|
||||||
|
catalog_name = "NubesLab"
|
||||||
|
network_name = "${vcd_network.foonet.name}"
|
||||||
|
memory = 1024
|
||||||
|
cpus = 1
|
||||||
|
ip = "10.10.102.160"
|
||||||
|
power_on = false
|
||||||
|
}
|
||||||
|
`
|
|
@ -0,0 +1,109 @@
|
||||||
|
package vcd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
types "github.com/opencredo/vmware-govcd/types/v56"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func expandIpRange(configured []interface{}) (types.IPRanges, error) {
|
||||||
|
ipRange := make([]*types.IPRange, 0, len(configured))
|
||||||
|
|
||||||
|
for _, ipRaw := range configured {
|
||||||
|
data := ipRaw.(map[string]interface{})
|
||||||
|
|
||||||
|
ip := types.IPRange{
|
||||||
|
StartAddress: data["start_address"].(string),
|
||||||
|
EndAddress: data["end_address"].(string),
|
||||||
|
}
|
||||||
|
|
||||||
|
ipRange = append(ipRange, &ip)
|
||||||
|
}
|
||||||
|
|
||||||
|
ipRanges := types.IPRanges{
|
||||||
|
IPRange: ipRange,
|
||||||
|
}
|
||||||
|
|
||||||
|
return ipRanges, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func expandFirewallRules(configured []interface{}, gateway *types.EdgeGateway) ([]*types.FirewallRule, error) {
|
||||||
|
//firewallRules := make([]*types.FirewallRule, 0, len(configured))
|
||||||
|
firewallRules := gateway.Configuration.EdgeGatewayServiceConfiguration.FirewallService.FirewallRule
|
||||||
|
|
||||||
|
for i := len(configured) - 1; i >= 0; i-- {
|
||||||
|
data := configured[i].(map[string]interface{})
|
||||||
|
|
||||||
|
var protocol *types.FirewallRuleProtocols
|
||||||
|
switch data["protocol"].(string) {
|
||||||
|
case "tcp":
|
||||||
|
protocol = &types.FirewallRuleProtocols{
|
||||||
|
TCP: true,
|
||||||
|
}
|
||||||
|
case "udp":
|
||||||
|
protocol = &types.FirewallRuleProtocols{
|
||||||
|
UDP: true,
|
||||||
|
}
|
||||||
|
case "icmp":
|
||||||
|
protocol = &types.FirewallRuleProtocols{
|
||||||
|
ICMP: true,
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
protocol = &types.FirewallRuleProtocols{
|
||||||
|
Any: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rule := &types.FirewallRule{
|
||||||
|
//ID: strconv.Itoa(len(configured) - i),
|
||||||
|
IsEnabled: true,
|
||||||
|
MatchOnTranslate: false,
|
||||||
|
Description: data["description"].(string),
|
||||||
|
Policy: data["policy"].(string),
|
||||||
|
Protocols: protocol,
|
||||||
|
Port: getNumericPort(data["destination_port"]),
|
||||||
|
DestinationPortRange: data["destination_port"].(string),
|
||||||
|
DestinationIP: data["destination_ip"].(string),
|
||||||
|
SourcePort: getNumericPort(data["source_port"]),
|
||||||
|
SourcePortRange: data["source_port"].(string),
|
||||||
|
SourceIP: data["source_ip"].(string),
|
||||||
|
EnableLogging: false,
|
||||||
|
}
|
||||||
|
firewallRules = append(firewallRules, rule)
|
||||||
|
}
|
||||||
|
|
||||||
|
return firewallRules, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getProtocol(protocol types.FirewallRuleProtocols) string {
|
||||||
|
if protocol.TCP {
|
||||||
|
return "tcp"
|
||||||
|
}
|
||||||
|
if protocol.UDP {
|
||||||
|
return "udp"
|
||||||
|
}
|
||||||
|
if protocol.ICMP {
|
||||||
|
return "icmp"
|
||||||
|
}
|
||||||
|
return "any"
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNumericPort(portrange interface{}) int {
|
||||||
|
i, err := strconv.Atoi(portrange.(string))
|
||||||
|
if err != nil {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPortString(port int) string {
|
||||||
|
if port == -1 {
|
||||||
|
return "any"
|
||||||
|
}
|
||||||
|
portstring := strconv.Itoa(port)
|
||||||
|
return portstring
|
||||||
|
}
|
||||||
|
|
||||||
|
func retryCall(min int, f resource.RetryFunc) error {
|
||||||
|
return resource.Retry(time.Duration(min)*time.Minute, f)
|
||||||
|
}
|
|
@ -24,6 +24,7 @@ body.layout-packet,
|
||||||
body.layout-rundeck,
|
body.layout-rundeck,
|
||||||
body.layout-template,
|
body.layout-template,
|
||||||
body.layout-tls,
|
body.layout-tls,
|
||||||
|
body.layout-vcd,
|
||||||
body.layout-vsphere,
|
body.layout-vsphere,
|
||||||
body.layout-docs,
|
body.layout-docs,
|
||||||
body.layout-downloads,
|
body.layout-downloads,
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
---
|
||||||
|
layout: "vcd"
|
||||||
|
page_title: "Provider: vCloudDirector"
|
||||||
|
sidebar_current: "docs-vcd-index"
|
||||||
|
description: |-
|
||||||
|
The vCloud Director provider is used to interact with the resources supported by vCloud
|
||||||
|
Director. The provider needs to be configured with the proper credentials before it can be used.
|
||||||
|
---
|
||||||
|
|
||||||
|
# vCloud Director Provider
|
||||||
|
|
||||||
|
The vCloud Director provider is used to interact with the resources supported by vCloud
|
||||||
|
Director. The provider needs to be configured with the proper credentials before it can be used.
|
||||||
|
|
||||||
|
Use the navigation to the left to read about the available resources.
|
||||||
|
|
||||||
|
~> **NOTE:** The vCloud Director Provider currently represents _initial support_ and
|
||||||
|
therefore may undergo significant changes as the community improves it.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
# Configure the vCloud Director Provider
|
||||||
|
provider "vcd" {
|
||||||
|
user = "${var.vcd_user}"
|
||||||
|
password = "${var.vcd_pass}"
|
||||||
|
org = "${var.vcd_org}"
|
||||||
|
url = "${var.vcd_url}"
|
||||||
|
vdc = "${var.vcd_vdc}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create a new network
|
||||||
|
resource "vcd_network" "net" {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are used to configure the vCloud Director Provider:
|
||||||
|
|
||||||
|
* `user` - (Required) This is the username for vCloud Director API operations. Can also
|
||||||
|
be specified with the `VCD_USER` environment variable.
|
||||||
|
* `password` - (Required) This is the password for vCloud Director API operations. Can
|
||||||
|
also be specified with the `VCD_PASSWORD` environment variable.
|
||||||
|
* `org` - (Required) This is the vCloud Director Org on which to run API
|
||||||
|
operations. Can also be specified with the `VCD_ORG` environment
|
||||||
|
variable.
|
||||||
|
* `url` - (Required) This is the URL for the vCloud Director API.
|
||||||
|
Can also be specified with the `VCD_URL` environment variable.
|
||||||
|
* `vdc` - (Optional) This is the virtual datacenter within vCloud Director to run
|
||||||
|
API operations against. If not set the plugin will select the first virtual
|
||||||
|
datacenter available to your Org. Can also be specified with the `VCD_VDC` environment
|
||||||
|
variable.
|
|
@ -0,0 +1,32 @@
|
||||||
|
---
|
||||||
|
layout: "vcd"
|
||||||
|
page_title: "vCloudDirector: vcd_dnat"
|
||||||
|
sidebar_current: "docs-vcd-resource-dnat"
|
||||||
|
description: |-
|
||||||
|
Provides a vCloud Director DNAT resource. This can be used to create, modify, and delete destination NATs to map external IPs to a VM.
|
||||||
|
---
|
||||||
|
|
||||||
|
# vcd\_dnat
|
||||||
|
|
||||||
|
Provides a vCloud Director DNAT resource. This can be used to create, modify,
|
||||||
|
and delete destination NATs to map an external IP/port to a VM.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
resource "vcd_dnat" "web" {
|
||||||
|
edge_gateway = "Edge Gateway Name"
|
||||||
|
external_ip = "78.101.10.20"
|
||||||
|
port = 80
|
||||||
|
internal_ip = "10.10.0.5"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are supported:
|
||||||
|
|
||||||
|
* `edge_gateway` - (Required) The name of the edge gateway on which to apply the DNAT
|
||||||
|
* `external_ip` - (Required) One of the external IPs available on your Edge Gateway
|
||||||
|
* `port` - (Required) The port number to map
|
||||||
|
* `internal_ip` - (Required) The IP of the VM to map to
|
|
@ -0,0 +1,63 @@
|
||||||
|
---
|
||||||
|
layout: "vcd"
|
||||||
|
page_title: "vCloudDirector: vcd_firewall_rules"
|
||||||
|
sidebar_current: "docs-vcd-resource-firewall-rules"
|
||||||
|
description: |-
|
||||||
|
Provides a vCloud Director Firewall resource. This can be used to create, modify, and delete firewall settings and rules.
|
||||||
|
---
|
||||||
|
|
||||||
|
# vcd\_firewall\_rules
|
||||||
|
|
||||||
|
Provides a vCloud Director Firewall resource. This can be used to create,
|
||||||
|
modify, and delete firewall settings and rules.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
resource "vcd_firewall_rules" "fw" {
|
||||||
|
edge_gateway = "Edge Gateway Name"
|
||||||
|
default_action = "drop"
|
||||||
|
|
||||||
|
rule {
|
||||||
|
description = "allow-web"
|
||||||
|
policy = "allow"
|
||||||
|
protocol = "tcp"
|
||||||
|
destination_port = "80"
|
||||||
|
destination_ip = "10.10.0.5"
|
||||||
|
source_port = "any"
|
||||||
|
source_ip = "any"
|
||||||
|
}
|
||||||
|
|
||||||
|
rule {
|
||||||
|
description = "allow-outbound"
|
||||||
|
policy = "allow"
|
||||||
|
protocol = "any"
|
||||||
|
destination_port = "any"
|
||||||
|
destination_ip = "any"
|
||||||
|
source_port = "any"
|
||||||
|
source_ip = "10.10.0.0/24"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are supported:
|
||||||
|
|
||||||
|
* `edge_gateway` - (Required) The name of the edge gateway on which to apply the Firewall Rules
|
||||||
|
* `default_action` - (Required) Either "allow" or "deny". Specifies what to do should none of the rules match
|
||||||
|
* `rule` - (Optional) Configures a firewall rule; see [Rules](#rules) below for details.
|
||||||
|
|
||||||
|
<a id="rules"></a>
|
||||||
|
## Rules
|
||||||
|
|
||||||
|
Each firewall rule supports the following attributes:
|
||||||
|
|
||||||
|
* `description` - (Required) Description of the fireall rule
|
||||||
|
* `policy` - (Required) Specifies what to do when this rule is matched. Either "allow" or "deny"
|
||||||
|
* `protocol` - (Required) The protocol to match. One of "tcp", "udp", "icmp" or "any"
|
||||||
|
* `destination_port` - (Required) The destination port to match. Either a port number or "any"
|
||||||
|
* `destination_ip` - (Required) The destination IP to match. Either an IP address, IP range or "any"
|
||||||
|
* `source_port` - (Required) The source port to match. Either a port number or "any"
|
||||||
|
* `source_ip` - (Required) The source IP to match. Either an IP address, IP range or "any"
|
|
@ -0,0 +1,57 @@
|
||||||
|
---
|
||||||
|
layout: "vcd"
|
||||||
|
page_title: "vCloudDirector: vcd_network"
|
||||||
|
sidebar_current: "docs-vcd-resource-network"
|
||||||
|
description: |-
|
||||||
|
Provides a vCloud Director VDC Network. This can be used to create, modify, and delete internal networks for vApps to connect.
|
||||||
|
---
|
||||||
|
|
||||||
|
# vcd\_network
|
||||||
|
|
||||||
|
Provides a vCloud Director VDC Network. This can be used to create,
|
||||||
|
modify, and delete internal networks for vApps to connect.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
resource "vcd_network" "net" {
|
||||||
|
name = "my-net"
|
||||||
|
edge_gateway = "Edge Gateway Name"
|
||||||
|
gateway = "10.10.0.1"
|
||||||
|
|
||||||
|
dhcp_pool {
|
||||||
|
start_address = "10.10.0.2"
|
||||||
|
end_address = "10.10.0.100"
|
||||||
|
}
|
||||||
|
|
||||||
|
static_ip_pool {
|
||||||
|
start_address = "10.10.0.152"
|
||||||
|
end_address = "10.10.0.254"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are supported:
|
||||||
|
|
||||||
|
* `name` - (Required) A unique name for the network
|
||||||
|
* `edge_gateway` - (Required) The name of the edge gateway
|
||||||
|
* `netmask` - (Optional) The netmask for the new network. Defaults to `255.255.255.0`
|
||||||
|
* `gateway` (Required) The gateway for this network
|
||||||
|
* `dns1` - (Optional) First DNS server to use. Defaults to `8.8.8.8`
|
||||||
|
* `dns2` - (Optional) Second DNS server to use. Defaults to `8.8.4.4`
|
||||||
|
* `dns_suffix` - (Optional) A FQDN for the virtual machines on this network
|
||||||
|
* `dhcp_pool` - (Optional) A range of IPs to issue to virtual machines that don't
|
||||||
|
have a static IP; see [IP Pools](#ip-pools) below for details.
|
||||||
|
* `static_ip_pool` - (Optional) A range of IPs permitted to be used as static IPs for
|
||||||
|
virtual machines; see [IP Pools](#ip-pools) below for details.
|
||||||
|
|
||||||
|
<a id="ip-pools"></a>
|
||||||
|
## IP Pools
|
||||||
|
|
||||||
|
Network interfaces support the following attributes:
|
||||||
|
|
||||||
|
* `start_address` - (Required) The first address in the IP Range
|
||||||
|
* `end_address` - (Required) The final address in the IP Range
|
|
@ -0,0 +1,30 @@
|
||||||
|
---
|
||||||
|
layout: "vcd"
|
||||||
|
page_title: "vCloudDirector: vcd_snat"
|
||||||
|
sidebar_current: "docs-vcd-resource-snat"
|
||||||
|
description: |-
|
||||||
|
Provides a vCloud Director SNAT resource. This can be used to create, modify, and delete source NATs to allow vApps to send external traffic.
|
||||||
|
---
|
||||||
|
|
||||||
|
# vcd\_snat
|
||||||
|
|
||||||
|
Provides a vCloud Director SNAT resource. This can be used to create, modify,
|
||||||
|
and delete source NATs to allow vApps to send external traffic.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
resource "vcd_snat" "outbound" {
|
||||||
|
edge_gateway = "Edge Gateway Name"
|
||||||
|
external_ip = "78.101.10.20"
|
||||||
|
internal_ip = "10.10.0.0/24"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are supported:
|
||||||
|
|
||||||
|
* `edge_gateway` - (Required) The name of the edge gateway on which to apply the SNAT
|
||||||
|
* `external_ip` - (Required) One of the external IPs available on your Edge Gateway
|
||||||
|
* `internal_ip` - (Required) The IP or IP Range of the VM(s) to map from
|
|
@ -0,0 +1,59 @@
|
||||||
|
---
|
||||||
|
layout: "vcd"
|
||||||
|
page_title: "vCloudDirector: vcd_vapp"
|
||||||
|
sidebar_current: "docs-vcd-resource-vapp"
|
||||||
|
description: |-
|
||||||
|
Provides a vCloud Director vApp resource. This can be used to create, modify, and delete vApps.
|
||||||
|
---
|
||||||
|
|
||||||
|
# vcd\_vapp
|
||||||
|
|
||||||
|
Provides a vCloud Director vApp resource. This can be used to create,
|
||||||
|
modify, and delete vApps.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
resource "vcd_network" "net" {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "vcd_vapp" "web" {
|
||||||
|
name = "web"
|
||||||
|
catalog_name = "Boxes"
|
||||||
|
template_name = "lampstack-1.10.1-ubuntu-10.04"
|
||||||
|
memory = 2048
|
||||||
|
cpus = 1
|
||||||
|
|
||||||
|
network_name = "${vcd_network.net.name}"
|
||||||
|
network_href = "${vcd_network.net.href}"
|
||||||
|
ip = "10.10.104.160"
|
||||||
|
|
||||||
|
metadata {
|
||||||
|
role = "web"
|
||||||
|
env = "staging"
|
||||||
|
version = "v1"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are supported:
|
||||||
|
|
||||||
|
* `name` - (Required) A unique name for the vApp
|
||||||
|
* `catalog_name` - (Required) The catalog name in which to find the given vApp Template
|
||||||
|
* `template_name` - (Required) The name of the vApp Template to use
|
||||||
|
* `memory` - (Optional) The amount of RAM (in MB) to allocate to the vApp
|
||||||
|
* `cpus` - (Optional) The number of virtual CPUs to allocate to the vApp
|
||||||
|
* `initscript` (Optional) A script to be run only on initial boot
|
||||||
|
* `network_name` - (Required) Name of the network this vApp should join
|
||||||
|
* `network_href` - (Optional) The vCloud Director generated href of the network this vApp
|
||||||
|
should join. If empty it will use the network name and query vCloud Director to discover
|
||||||
|
this
|
||||||
|
* `ip` - (Optional) The IP to assign to this vApp. If given the address must be within the `static_ip_pool`
|
||||||
|
set for the network. If left blank, and the network has `dhcp_pool` set with at least one available IP then
|
||||||
|
this will be set with DHCP
|
||||||
|
* `metadata` - (Optional) Key value map of metadata to assign to this vApp
|
||||||
|
* `power_on` - (Optional) A boolean value stating if this vApp should be powered on. Default to `true`
|
|
@ -193,9 +193,14 @@
|
||||||
<a href="/docs/providers/tls/index.html">TLS</a>
|
<a href="/docs/providers/tls/index.html">TLS</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li<%= sidebar_current("docs-providers-vsphere") %>>
|
<li<%= sidebar_current("docs-providers-vcd") %>>
|
||||||
|
<a href="/docs/providers/vcd/index.html">vCloud Director</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li<%= sidebar_current("docs-providers-vsphere") %>>
|
||||||
<a href="/docs/providers/vsphere/index.html">vSphere</a>
|
<a href="/docs/providers/vsphere/index.html">vSphere</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
<% wrap_layout :inner do %>
|
||||||
|
<% content_for :sidebar do %>
|
||||||
|
<div class="docs-sidebar hidden-print affix-top" role="complementary">
|
||||||
|
<ul class="nav docs-sidenav">
|
||||||
|
<li<%= sidebar_current("docs-home") %>>
|
||||||
|
<a href="/docs/providers/index.html">« Documentation Home</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li<%= sidebar_current("docs-vcd-index") %>>
|
||||||
|
<a href="/docs/providers/vcd/index.html">vCloudDirector Provider</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li<%= sidebar_current(/^docs-vcd-resource/) %>>
|
||||||
|
<a href="#">Resources</a>
|
||||||
|
<ul class="nav nav-visible">
|
||||||
|
<li<%= sidebar_current("docs-vcd-resource-dnat") %>>
|
||||||
|
<a href="/docs/providers/vcd/r/dnat.html">vcd_dnat</a>
|
||||||
|
</li>
|
||||||
|
<li<%= sidebar_current("docs-vcd-resource-firewall-rules") %>>
|
||||||
|
<a href="/docs/providers/vcd/r/firewall_rules.html">vcd_firewall_rules</a>
|
||||||
|
</li>
|
||||||
|
<li<%= sidebar_current("docs-vcd-resource-network") %>>
|
||||||
|
<a href="/docs/providers/vcd/r/network.html">vcd_network</a>
|
||||||
|
</li>
|
||||||
|
<li<%= sidebar_current("docs-vcd-resource-snat") %>>
|
||||||
|
<a href="/docs/providers/vcd/r/snat.html">vcd_snat</a>
|
||||||
|
</li>
|
||||||
|
<li<%= sidebar_current("docs-vcd-resource-vapp") %>>
|
||||||
|
<a href="/docs/providers/vcd/r/vapp.html">vcd_vapp</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<%= yield %>
|
||||||
|
<% end %>
|
Loading…
Reference in New Issue