diff --git a/.changes/v3.8.0/929-improvements.md b/.changes/v3.8.0/929-improvements.md new file mode 100644 index 000000000..ada8a0069 --- /dev/null +++ b/.changes/v3.8.0/929-improvements.md @@ -0,0 +1,2 @@ +* Resource and data source `vcd_nsxt_network_dhcp` support Isolated networks, different DHCP modes + ('EDGE', 'NETWORK', 'DHCP') and lease time [GH-929] diff --git a/go.mod b/go.mod index aa47c8a02..be5f0c747 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/hashicorp/go-version v1.6.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.1 github.com/kr/pretty v0.2.1 - github.com/vmware/go-vcloud-director/v2 v2.17.0-alpha.8 + github.com/vmware/go-vcloud-director/v2 v2.17.0-alpha.9 ) require ( diff --git a/go.sum b/go.sum index 2bf05aac0..9a8ab2f22 100644 --- a/go.sum +++ b/go.sum @@ -178,8 +178,8 @@ github.com/vmihailenco/msgpack/v4 v4.3.12 h1:07s4sz9IReOgdikxLTKNbBdqDMLsjPKXwvC github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= github.com/vmihailenco/tagparser v0.1.1 h1:quXMXlA39OCbd2wAdTsGDlK9RkOk6Wuw+x37wVyIuWY= github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= -github.com/vmware/go-vcloud-director/v2 v2.17.0-alpha.8 h1:qUyPHup11h2RQad852UwAyvCZhLm6obdLLmIT33acgA= -github.com/vmware/go-vcloud-director/v2 v2.17.0-alpha.8/go.mod h1:KjnB8t5l1bRrc+jLKDJbx0vZLRzz2RPzNQ7xzg7yI3o= +github.com/vmware/go-vcloud-director/v2 v2.17.0-alpha.9 h1:dBf7JY4UYQlsnvgl1mVWimirdDyLdWNHGRZvbHcnFFU= +github.com/vmware/go-vcloud-director/v2 v2.17.0-alpha.9/go.mod h1:KjnB8t5l1bRrc+jLKDJbx0vZLRzz2RPzNQ7xzg7yI3o= github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI= github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s= diff --git a/scripts/skip-upgrade-tests.txt b/scripts/skip-upgrade-tests.txt index 9e40f6eb5..202829769 100644 --- a/scripts/skip-upgrade-tests.txt +++ b/scripts/skip-upgrade-tests.txt @@ -230,3 +230,4 @@ vcd.ResourceSchema-vcd_vapp.tf v3.7.0 "Deprecated 'metadata' attribute is now Co vcd.ResourceSchema-vcd_vapp_vm.tf v3.7.0 "Deprecated 'metadata' attribute is now Computed (PR 917)" vcd.ResourceSchema-vcd_vm.tf v3.7.0 "Deprecated 'metadata' attribute is now Computed (PR 917)" vcd.TestAccVcdStandaloneVmTemplate.tf v3.7.0 "Added 'status', 'status_text' and 'metadata_entry' computed attributes (PR 901)" +vcd.ResourceSchema-vcd_nsxt_network_dhcp.tf v3.7.0 "Added 'mode', 'lease_time' and 'listener_ip_address' computed attributes (PR 929)" diff --git a/vcd/config_test.go b/vcd/config_test.go index 30e91206e..2c5e88f97 100644 --- a/vcd/config_test.go +++ b/vcd/config_test.go @@ -1107,7 +1107,7 @@ func importStateIdOrgNsxtVdcObject(objectName string) resource.ImportStateIdFunc // Group (such as Vapp, networks, edge gateway) in NSX-T VDC func importStateIdOrgNsxtVdcGroupObject(vdcGroupName, objectName string) resource.ImportStateIdFunc { return func(*terraform.State) (string, error) { - if testConfig.VCD.Org == "" || testConfig.Nsxt.Vdc == "" || objectName == "" { + if testConfig.VCD.Org == "" || objectName == "" { return "", fmt.Errorf("missing information to generate import path") } return testConfig.VCD.Org + diff --git a/vcd/datasource_vcd_nsxt_network_dhcp.go b/vcd/datasource_vcd_nsxt_network_dhcp.go index 1acc0f225..9fad86578 100644 --- a/vcd/datasource_vcd_nsxt_network_dhcp.go +++ b/vcd/datasource_vcd_nsxt_network_dhcp.go @@ -46,6 +46,11 @@ func datasourceVcdOpenApiDhcp() *schema.Resource { ForceNew: true, Description: "Parent Org VDC network name", }, + "mode": { + Type: schema.TypeString, + Computed: true, + Description: "DHCP mode. One of 'EDGE', 'NETWORK', 'RELAY'", + }, "pool": { Type: schema.TypeSet, Computed: true, @@ -61,6 +66,16 @@ func datasourceVcdOpenApiDhcp() *schema.Resource { Type: schema.TypeString, }, }, + "lease_time": { + Type: schema.TypeInt, + Computed: true, + Description: "Lease time in seconds", + }, + "listener_ip_address": { + Type: schema.TypeString, + Computed: true, + Description: "IP Address of DHCP server in network", + }, }, } } diff --git a/vcd/resource_vcd_nsxt_network_dhcp.go b/vcd/resource_vcd_nsxt_network_dhcp.go index 6ef95880a..2d3669b5f 100644 --- a/vcd/resource_vcd_nsxt_network_dhcp.go +++ b/vcd/resource_vcd_nsxt_network_dhcp.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) var nsxtDhcpPoolSetSchema = &schema.Resource{ @@ -58,9 +59,19 @@ func resourceVcdOpenApiDhcp() *schema.Resource { ForceNew: true, Description: "Parent Org VDC network ID", }, + "mode": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Default: "EDGE", + ValidateFunc: validation.StringInSlice([]string{"EDGE", "NETWORK", "RELAY"}, false), + Description: "DHCP mode. One of 'EDGE' (default), 'NETWORK', 'RELAY'", + }, "pool": { - Type: schema.TypeSet, - Required: true, + Type: schema.TypeSet, + // Pool specification is optional, because mode=RELAY requires to have no pool + // configuration + Optional: true, Description: "IP ranges used for DHCP pool allocation in the network", Elem: nsxtDhcpPoolSetSchema, }, @@ -73,6 +84,21 @@ func resourceVcdOpenApiDhcp() *schema.Resource { Type: schema.TypeString, }, }, + "lease_time": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + Description: "Lease time in seconds", + }, + "listener_ip_address": { + Type: schema.TypeString, + // API still does not allow to change IP address in 10.4.0, but the error is human + // readable and it might allow changing in future. For this reason ForceNew remains + // commented. + // ForceNew: true, + Optional: true, + Description: "IP Address of DHCP server in network. Only applicable when mode=NETWORK", + }, }, } } @@ -206,31 +232,29 @@ func resourceVcdOpenApiDhcpImport(_ context.Context, d *schema.ResourceData, met func getOpenAPIOrgVdcNetworkDhcpType(d *schema.ResourceData) *types.OpenApiOrgVdcNetworkDhcp { orgVdcNetDhcp := &types.OpenApiOrgVdcNetworkDhcp{ DhcpPools: nil, + Mode: d.Get("mode").(string), } - dhcpPool := d.Get("pool") - if dhcpPool == nil { - return orgVdcNetDhcp - } - - dhcpPoolSet := dhcpPool.(*schema.Set) - dhcpPoolList := dhcpPoolSet.List() - - if len(dhcpPoolList) > 0 { - dhcpPools := make([]types.OpenApiOrgVdcNetworkDhcpPools, len(dhcpPoolList)) - for index, pool := range dhcpPoolList { - poolMap := pool.(map[string]interface{}) - onePool := types.OpenApiOrgVdcNetworkDhcpPools{ - IPRange: types.OpenApiOrgVdcNetworkDhcpIpRange{ - StartAddress: poolMap["start_address"].(string), - EndAddress: poolMap["end_address"].(string), - }, + if dhcpPool, dhcpPoolIsSet := d.GetOk("pool"); dhcpPoolIsSet { + dhcpPoolSet := dhcpPool.(*schema.Set) + dhcpPoolList := dhcpPoolSet.List() + + if len(dhcpPoolList) > 0 { + dhcpPools := make([]types.OpenApiOrgVdcNetworkDhcpPools, len(dhcpPoolList)) + for index, pool := range dhcpPoolList { + poolMap := pool.(map[string]interface{}) + onePool := types.OpenApiOrgVdcNetworkDhcpPools{ + IPRange: types.OpenApiOrgVdcNetworkDhcpIpRange{ + StartAddress: poolMap["start_address"].(string), + EndAddress: poolMap["end_address"].(string), + }, + } + dhcpPools[index] = onePool } - dhcpPools[index] = onePool - } - // Inject data into main structure - orgVdcNetDhcp.DhcpPools = dhcpPools + // Inject data into main structure + orgVdcNetDhcp.DhcpPools = dhcpPools + } } dnsServers, ok := d.GetOk("dns_servers") @@ -242,6 +266,15 @@ func getOpenAPIOrgVdcNetworkDhcpType(d *schema.ResourceData) *types.OpenApiOrgVd orgVdcNetDhcp.DnsServers = dnsServerSet } + if leaseTime, isLeaseTimeSet := d.GetOk("lease_time"); isLeaseTimeSet { + leaseTimeInt := leaseTime.(int) + orgVdcNetDhcp.LeaseTime = &leaseTimeInt + } + + if ipAddress, ipAddressIsSet := d.GetOk("listener_ip_address"); ipAddressIsSet { + orgVdcNetDhcp.IPAddress = ipAddress.(string) + } + return orgVdcNetDhcp } @@ -272,5 +305,13 @@ func setOpenAPIOrgVdcNetworkDhcpData(orgNetworkId string, orgVdcNetwork *types.O } } + dSet(d, "mode", orgVdcNetwork.Mode) + if orgVdcNetwork.LeaseTime != nil { + dSet(d, "lease_time", *orgVdcNetwork.LeaseTime) + } + if orgVdcNetwork.IPAddress != "" { + dSet(d, "listener_ip_address", orgVdcNetwork.IPAddress) + } + return nil } diff --git a/vcd/resource_vcd_nsxt_network_dhcp_test.go b/vcd/resource_vcd_nsxt_network_dhcp_test.go index 2315a0746..c5e819262 100644 --- a/vcd/resource_vcd_nsxt_network_dhcp_test.go +++ b/vcd/resource_vcd_nsxt_network_dhcp_test.go @@ -60,6 +60,9 @@ func TestAccVcdOpenApiDhcpNsxtRouted(t *testing.T) { Config: configText, Check: resource.ComposeAggregateTestCheckFunc( resource.TestMatchResourceAttr("vcd_nsxt_network_dhcp.pools", "id", regexp.MustCompile(`^urn:vcloud:network:.*$`)), + resource.TestCheckResourceAttr("vcd_nsxt_network_dhcp.pools", "lease_time", "86400"), + resource.TestCheckResourceAttr("vcd_nsxt_network_dhcp.pools", "mode", "EDGE"), + resource.TestCheckNoResourceAttr("vcd_nsxt_network_dhcp.pools", "listener_ip_address"), resource.TestCheckTypeSetElemNestedAttrs("vcd_nsxt_network_dhcp.pools", "pool.*", map[string]string{ "start_address": "7.1.1.100", "end_address": "7.1.1.110", @@ -70,6 +73,9 @@ func TestAccVcdOpenApiDhcpNsxtRouted(t *testing.T) { Config: configText1, Check: resource.ComposeAggregateTestCheckFunc( resource.TestMatchResourceAttr("vcd_nsxt_network_dhcp.pools", "id", regexp.MustCompile(`^urn:vcloud:network:.*$`)), + resource.TestCheckResourceAttr("vcd_nsxt_network_dhcp.pools", "lease_time", "4294967295"), + resource.TestCheckResourceAttr("vcd_nsxt_network_dhcp.pools", "mode", "EDGE"), + resource.TestCheckNoResourceAttr("vcd_nsxt_network_dhcp.pools", "listener_ip_address"), resource.TestCheckTypeSetElemNestedAttrs("vcd_nsxt_network_dhcp.pools", "pool.*", map[string]string{ "start_address": "7.1.1.100", "end_address": "7.1.1.110", @@ -92,6 +98,9 @@ func TestAccVcdOpenApiDhcpNsxtRouted(t *testing.T) { SkipFunc: vcdVersionIsLowerThan1031, Check: resource.ComposeAggregateTestCheckFunc( resource.TestMatchResourceAttr("vcd_nsxt_network_dhcp.pools", "id", regexp.MustCompile(`^urn:vcloud:network:.*$`)), + resource.TestCheckResourceAttr("vcd_nsxt_network_dhcp.pools", "lease_time", "4294967295"), + resource.TestCheckResourceAttr("vcd_nsxt_network_dhcp.pools", "mode", "EDGE"), + resource.TestCheckNoResourceAttr("vcd_nsxt_network_dhcp.pools", "listener_ip_address"), resource.TestCheckTypeSetElemNestedAttrs("vcd_nsxt_network_dhcp.pools", "pool.*", map[string]string{ "start_address": "7.1.1.100", "end_address": "7.1.1.110", @@ -155,6 +164,8 @@ resource "vcd_nsxt_network_dhcp" "pools" { vdc = "{{.NsxtVdc}}" org_network_id = vcd_network_routed_v2.net1.id + mode = "EDGE" + lease_time = 4294967295 # maximum allowed lease time in seconds (~49 days) pool { start_address = "7.1.1.100" @@ -188,3 +199,295 @@ resource "vcd_nsxt_network_dhcp" "pools" { dns_servers = ["1.1.1.1", "1.0.0.1"] } ` + +// TestAccVcdOpenApiDhcpNsxtIsolated checks that DHCP works in NSX-T Isolated networks. +// It requires a VDC with assigned Edge Cluster to work therefore it creates its own VDC +func TestAccVcdOpenApiDhcpNsxtIsolated(t *testing.T) { + preTestChecks(t) + + // Requires VCD 10.3.1+ + vcdClient := createTemporaryVCDConnection(true) + if vcdClient == nil || vcdClient.Client.APIVCDMaxVersionIs("< 36.1") { + t.Skipf("NSX-T Isolated network DHCP requires VCD 10.3.1+ (API v36.1+)") + } + + // String map to fill the template + var params = StringMap{ + "Org": testConfig.VCD.Org, + "NetworkName": t.Name(), + "VdcName": t.Name(), + "ProviderVdc": testConfig.VCD.NsxtProviderVdc.Name, + "NetworkPool": testConfig.VCD.NsxtProviderVdc.NetworkPool, + "ProviderVdcStorageProfile": testConfig.VCD.NsxtProviderVdc.StorageProfile, + "EdgeCluster": testConfig.Nsxt.NsxtEdgeCluster, + + "Tags": "network nsxt", + } + testParamsNotEmpty(t, params) + + configText1 := templateFill(testAccRoutedNetDhcpIsolatedStep1, params) + debugPrintf("#[DEBUG] CONFIGURATION for step 1: %s", configText1) + + params["FuncName"] = t.Name() + "-step2" + configText2 := templateFill(testAccRoutedNetDhcpIsolatedStep2, params) + debugPrintf("#[DEBUG] CONFIGURATION for step 2: %s", configText2) + + params["FuncName"] = t.Name() + "-step4DS" + configText4 := templateFill(testAccRoutedNetDhcpIsolatedStep2DS, params) + debugPrintf("#[DEBUG] CONFIGURATION for step 4: %s", configText4) + + if vcdShortTest { + t.Skip(acceptanceTestsSkipped) + return + } + + // This case is specific for VCD 10.3.1 onwards since dns servers are not present in previous versions + // var configText2 string + // if vcdClient != nil && vcdClient.Client.APIVCDMaxVersionIs(">= 36.1") { + // params["SkipTest"] = "# skip-binary-test: VCD 10.3.1 onwards dns servers are not present in previous versions" + // } + // params["FuncName"] = t.Name() + "-step2" + // configText2 = templateFill(testAccRoutedNetDhcpStep3, params) + // debugPrintf("#[DEBUG] CONFIGURATION for step 2: %s", configText2) + + resource.Test(t, resource.TestCase{ + ProviderFactories: testAccProviders, + CheckDestroy: testAccCheckOpenApiVcdNetworkDestroy(testConfig.Nsxt.Vdc, "nsxt-routed-dhcp"), + Steps: []resource.TestStep{ + { + Config: configText1, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestMatchResourceAttr("vcd_nsxt_network_dhcp.pools", "id", regexp.MustCompile(`^urn:vcloud:network:.*$`)), + resource.TestCheckResourceAttr("vcd_nsxt_network_dhcp.pools", "lease_time", "86400"), + resource.TestCheckResourceAttr("vcd_nsxt_network_dhcp.pools", "mode", "NETWORK"), + resource.TestCheckResourceAttr("vcd_nsxt_network_dhcp.pools", "listener_ip_address", "7.1.1.254"), + resource.TestCheckResourceAttr("vcd_nsxt_network_dhcp.pools", "pool.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs("vcd_nsxt_network_dhcp.pools", "pool.*", map[string]string{ + "start_address": "7.1.1.100", + "end_address": "7.1.1.110", + }), + ), + }, + { + Config: configText2, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestMatchResourceAttr("vcd_nsxt_network_dhcp.pools", "id", regexp.MustCompile(`^urn:vcloud:network:.*$`)), + resource.TestCheckResourceAttr("vcd_nsxt_network_dhcp.pools", "lease_time", "60"), + resource.TestCheckResourceAttr("vcd_nsxt_network_dhcp.pools", "mode", "NETWORK"), + resource.TestCheckResourceAttr("vcd_nsxt_network_dhcp.pools", "pool.#", "2"), + resource.TestCheckResourceAttr("vcd_nsxt_network_dhcp.pools", "listener_ip_address", "7.1.1.254"), + resource.TestCheckTypeSetElemNestedAttrs("vcd_nsxt_network_dhcp.pools", "pool.*", map[string]string{ + "start_address": "7.1.1.100", + "end_address": "7.1.1.110", + }), + resource.TestCheckTypeSetElemNestedAttrs("vcd_nsxt_network_dhcp.pools", "pool.*", map[string]string{ + "start_address": "7.1.1.120", + "end_address": "7.1.1.140", + }), + ), + }, + { + Config: configText1, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestMatchResourceAttr("vcd_nsxt_network_dhcp.pools", "id", regexp.MustCompile(`^urn:vcloud:network:.*$`)), + resource.TestCheckResourceAttr("vcd_nsxt_network_dhcp.pools", "lease_time", "60"), + resource.TestCheckResourceAttr("vcd_nsxt_network_dhcp.pools", "pool.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs("vcd_nsxt_network_dhcp.pools", "pool.*", map[string]string{ + "start_address": "7.1.1.100", + "end_address": "7.1.1.110", + }), + ), + }, + { + Config: configText4, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestMatchResourceAttr("vcd_nsxt_network_dhcp.pools", "id", regexp.MustCompile(`^urn:vcloud:network:.*$`)), + resourceFieldsEqual("data.vcd_nsxt_network_dhcp.pools", "vcd_nsxt_network_dhcp.pools", nil), + ), + }, + { + ResourceName: "vcd_nsxt_network_dhcp.pools", + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: importStateIdOrgNsxtVdcGroupObject(params["VdcName"].(string), params["NetworkName"].(string)), + ImportStateVerifyIgnore: []string{"vdc"}, + }, + }, + }) + postTestChecks(t) +} + +const testAccRoutedNetDhcpIsolated = ` +data "vcd_provider_vdc" "pvdc" { + name = "{{.ProviderVdc}}" +} + +data "vcd_nsxt_edge_cluster" "ec" { + provider_vdc_id = data.vcd_provider_vdc.pvdc.id + name = "{{.EdgeCluster}}" +} + +resource "vcd_org_vdc" "with-edge-cluster" { + name = "{{.VdcName}}" + org = "{{.Org}}" + + allocation_model = "ReservationPool" + network_pool_name = "{{.NetworkPool}}" + provider_vdc_name = data.vcd_provider_vdc.pvdc.name + network_quota = 5 + + edge_cluster_id = data.vcd_nsxt_edge_cluster.ec.id + + compute_capacity { + cpu { + allocated = 1024 + limit = 1024 + } + + memory { + allocated = 1024 + limit = 1024 + } + } + + storage_profile { + name = "{{.ProviderVdcStorageProfile}}" + enabled = true + limit = 10240 + default = true + } + + enabled = true + enable_thin_provisioning = true + enable_fast_provisioning = true + delete_force = true + delete_recursive = true +} + +resource "vcd_network_isolated_v2" "net1" { + org = "{{.Org}}" + owner_id = vcd_org_vdc.with-edge-cluster.id + name = "{{.NetworkName}}" + + gateway = "7.1.1.1" + prefix_length = 24 + + static_ip_pool { + start_address = "7.1.1.10" + end_address = "7.1.1.20" + } +} +` + +const testAccRoutedNetDhcpIsolatedStep1 = testAccRoutedNetDhcpIsolated + ` +resource "vcd_nsxt_network_dhcp" "pools" { + org = "{{.Org}}" + vdc = vcd_org_vdc.with-edge-cluster.name + + org_network_id = vcd_network_isolated_v2.net1.id + mode = "NETWORK" + listener_ip_address = "7.1.1.254" + + pool { + start_address = "7.1.1.100" + end_address = "7.1.1.110" + } +} +` + +const testAccRoutedNetDhcpIsolatedStep2 = testAccRoutedNetDhcpIsolated + ` +resource "vcd_nsxt_network_dhcp" "pools" { + org = "{{.Org}}" + vdc = vcd_org_vdc.with-edge-cluster.name + + org_network_id = vcd_network_isolated_v2.net1.id + mode = "NETWORK" + listener_ip_address = "7.1.1.254" + lease_time = 60 + + pool { + start_address = "7.1.1.100" + end_address = "7.1.1.110" + } + + pool { + start_address = "7.1.1.120" + end_address = "7.1.1.140" + } +} +` + +const testAccRoutedNetDhcpIsolatedStep2DS = testAccRoutedNetDhcpIsolatedStep2 + ` +# skip-binary-test: cannot test resource and data source in binary test mode +data "vcd_nsxt_network_dhcp" "pools" { + org = vcd_nsxt_network_dhcp.pools.org + vdc = vcd_nsxt_network_dhcp.pools.vdc + + org_network_id = vcd_nsxt_network_dhcp.pools.org_network_id +} +` + +// TestAccVcdOpenApiDhcpNsxtRoutedRelay tests RELAY mode for DHCP. +// TODO we do not yet have a DHCP Forwarding resource (configured in Edge Gateway) therefore this +// test was run with DHCP forwarding manually configured. Improve and and uncomment this test when +// DHCP Forwarding resource is created and can be used here +// func TestAccVcdOpenApiDhcpNsxtRoutedRelay(t *testing.T) { +// preTestChecks(t) + +// // Requires VCD 10.3.1+ +// vcdClient := createTemporaryVCDConnection(true) +// if vcdClient == nil && vcdClient.Client.APIVCDMaxVersionIs("< 36.1") { +// t.Skipf("NSX-T Isolated network DHCP requires VCD 10.3.1+ (API v36.1+)") +// } + +// // String map to fill the template +// var params = StringMap{ +// "Org": testConfig.VCD.Org, +// "NsxtVdc": testConfig.Nsxt.Vdc, +// "EdgeGw": testConfig.Nsxt.EdgeGateway, +// "NetworkName": t.Name(), +// "Tags": "network nsxt", +// } +// testParamsNotEmpty(t, params) + +// configText1 := templateFill(testAccRoutedNetRelayDhcpStep1, params) +// debugPrintf("#[DEBUG] CONFIGURATION for step 0: %s", configText1) + +// if vcdShortTest { +// t.Skip(acceptanceTestsSkipped) +// return +// } + +// resource.Test(t, resource.TestCase{ +// ProviderFactories: testAccProviders, +// CheckDestroy: testAccCheckOpenApiVcdNetworkDestroy(testConfig.Nsxt.Vdc, "nsxt-routed-dhcp"), +// Steps: []resource.TestStep{ +// { +// Config: configText1, +// Check: resource.ComposeAggregateTestCheckFunc( +// resource.TestMatchResourceAttr("vcd_nsxt_network_dhcp.pools", "id", regexp.MustCompile(`^urn:vcloud:network:.*$`)), +// resource.TestCheckResourceAttr("vcd_nsxt_network_dhcp.pools", "mode", "RELAY"), +// resource.TestCheckResourceAttr("vcd_nsxt_network_dhcp.pools", "pool.#", "0"), +// ), +// }, +// { +// ResourceName: "vcd_nsxt_network_dhcp.pools", +// ImportState: true, +// ImportStateVerify: true, +// ImportStateIdFunc: importStateIdOrgNsxtVdcObject("nsxt-routed-dhcp"), +// ImportStateVerifyIgnore: []string{"vdc"}, +// }, +// }, +// }) +// postTestChecks(t) +// } + +// const testAccRoutedNetRelayDhcpStep1 = testAccRoutedNetDhcpConfig + ` +// resource "vcd_nsxt_network_dhcp" "pools" { +// org = "{{.Org}}" +// vdc = "{{.NsxtVdc}}" + +// org_network_id = vcd_network_routed_v2.net1.id +// mode = "RELAY" +// } +// ` diff --git a/vcd/resource_vcd_org_vdc_nsxt_edge_cluster_test.go b/vcd/resource_vcd_org_vdc_nsxt_edge_cluster_test.go index eba7ae174..0ebb717d3 100644 --- a/vcd/resource_vcd_org_vdc_nsxt_edge_cluster_test.go +++ b/vcd/resource_vcd_org_vdc_nsxt_edge_cluster_test.go @@ -139,7 +139,6 @@ resource "vcd_org_vdc" "with-edge-cluster" { enable_fast_provisioning = true delete_force = true delete_recursive = true - } ` diff --git a/website/docs/d/nsxt_network_dhcp.html.markdown b/website/docs/d/nsxt_network_dhcp.html.markdown index 6cc1b0703..20c57f7fb 100644 --- a/website/docs/d/nsxt_network_dhcp.html.markdown +++ b/website/docs/d/nsxt_network_dhcp.html.markdown @@ -3,12 +3,12 @@ layout: "vcd" page_title: "VMware Cloud Director: vcd_nsxt_network_dhcp" sidebar_current: "docs-vcd-datasource-nsxt-network-dhcp" description: |- - Provides a data source to read DHCP pools for NSX-T Org VDC Routed network. + Provides a data source to read DHCP pools for NSX-T Org VDC networks. --- # vcd\_nsxt\_network\_dhcp -Provides a data source to read DHCP pools for NSX-T Org VDC Routed network. +Provides a data source to read DHCP pools for NSX-T Org VDC networks. ## Example Usage 1 @@ -24,7 +24,7 @@ data "vcd_network_routed_v2" "parent" { data "vcd_nsxt_network_dhcp" "pools" { org = "my-org" - org_network_id = vcd_network_routed_v2.parent.id + org_network_id = data.vcd_network_routed_v2.parent.id } ``` diff --git a/website/docs/r/nsxt_network_dhcp.html.markdown b/website/docs/r/nsxt_network_dhcp.html.markdown index 645c7a819..501d00746 100644 --- a/website/docs/r/nsxt_network_dhcp.html.markdown +++ b/website/docs/r/nsxt_network_dhcp.html.markdown @@ -3,22 +3,14 @@ layout: "vcd" page_title: "VMware Cloud Director: vcd_nsxt_network_dhcp" sidebar_current: "docs-vcd-resource-nsxt-network-dhcp" description: |- - Provides a resource to manage DHCP pools for NSX-T Org VDC Routed network. + Provides a resource to manage DHCP pools for NSX-T Org VDC networks. --- # vcd\_nsxt\_network\_dhcp -Provides a resource to manage DHCP pools for NSX-T Org VDC Routed network. +Provides a resource to manage DHCP pools for NSX-T Org VDC networks. -## Specific usage notes - -**DHCP pool support** for NSX-T Org networks is **limited** by the VCD in the following ways: - -* VCD 10.2 only allows to remove all DHCP pools at once (terraform destroy/resource removal) - -* VCD 10.3+ allows to add and remove DHCP pools one by one - -## Example Usage 1 +## Example Usage 1 (Routed Org VDC Network with EDGE mode) ```hcl resource "vcd_network_routed_v2" "parent-network" { @@ -50,26 +42,65 @@ resource "vcd_nsxt_network_dhcp" "pools" { } ``` -## Example Usage 2 (Pool removal on VCD 10.2.0) - -DHCP pool definitions can only be removed all at once and not one by one. To do so in Terraform one -needs to destroy and create the resource. One can also achieve that by tainting the resource using -Terraform native `taint` command. Example below: - -* Define the network and DHCP pools as in [Example Usage 1](#example-usage-1) -* Use `terraform taint` on the parent network to force recreation: - ```sh - # terraform taint vcd_network_routed_v2.parent-network - Resource instance vcd_nsxt_network_dhcp.pools has been marked as tainted. - ``` -* Modify/remove `vcd_nsxt_network_dhcp` definition as per your needs -* Perform `terraform apply`. This will recreate tainted parent Org VDC network and new DHCP pools if defined. -You will see a WARNING during removal but it will not break : -```sh -vcd_nsxt_network_dhcp.pools: Destroying... [id=urn:vcloud:network:74754019-31f1-41ea-a9e2-fc21455d6d2b] -vcd_nsxt_network_dhcp.pools: Destruction complete after 11s -vcd_nsxt_network_dhcp.pools: Creating... -vcd_nsxt_network_dhcp.pools: Creation complete after 21s [id=urn:vcloud:network:74754019-31f1-41ea-a9e2-fc21455d6d2b] +## Example Usage 2 (Isolated Org VDC Network with NETWORK mode) +```hcl +resource "vcd_network_isolated_v2" "net1" { + org = "cloud" + owner_id = vcd_org_vdc.with-edge-cluster.id # VDC ID with Edge Cluster configured + name = "private-network" + + gateway = "7.1.1.1" + prefix_length = 24 + + static_ip_pool { + start_address = "7.1.1.10" + end_address = "7.1.1.20" + } +} + +resource "vcd_nsxt_network_dhcp" "pools" { + org = "cloud" + vdc = vcd_org_vdc.with-edge-cluster.name + + org_network_id = vcd_network_isolated_v2.net1.id + mode = "NETWORK" + listener_ip_address = "7.1.1.254" + + pool { + start_address = "7.1.1.100" + end_address = "7.1.1.110" + } +} +``` + +## Example Usage 3 (Routed Org VDC Network with RELAY mode) +```hcl +resource "vcd_network_routed_v2" "net1" { + org = "cloud" + vdc = "nsxt-vdc-cloud" + name = "nsxt-routed-dhcp" + + edge_gateway_id = data.vcd_nsxt_edgegateway.existing.id + + gateway = "7.1.1.1" + prefix_length = 24 + + static_ip_pool { + start_address = "7.1.1.10" + end_address = "7.1.1.20" + } +} + +resource "vcd_nsxt_network_dhcp" "pools" { + org = "cloud" + vdc = "nsxt-vdc-cloud" + + org_network_id = vcd_network_routed_v2.net1.id + + # DHCP forwarding must be configured on NSX-T Edge Gateway + # for RELAY mode + mode = "RELAY" +} ``` ## Argument Reference @@ -78,11 +109,21 @@ The following arguments are supported: * `org` - (Optional) The name of organization to use, optional if defined at provider level. Useful when connected as sysadmin working across different organisations. -* `org_network_id` - (Required) ID of parent Org VDC Routed network -* `pool` - (Required) One or more blocks to define DHCP pool ranges. See [Pools](#pools) and example -for usage details. -* `dns_servers` - (Optional; *v3.7+*) - The DNS server IPs to be assigned by this DHCP service. Maximum two values. -This argument is supported from VCD 10.3.1+. +* `org_network_id` - (Required) ID of parent Org VDC Routed network. +* `pool` - (Optional) One or more blocks to define DHCP pool ranges. Must not be set when + `mode=RELAY`. See [Pools](#pools) and example for usage details. +* `mode` - (Optional; *v3.8+*) One of `EDGE`, `NETWORK` or `RELAY`. Default is `EDGE` + * `EDGE` can be used with Routed Org VDC networks. + * `NETWORK` can be used for Isolated and Routed Org VDC networks. It requires + `listener_ip_address` to be set and Edge Cluster must be assigned to VDC. + * `RELAY` can be used with Routed Org VDC networks, but requires DHCP forwarding configuration in + NSX-T Edge Gateway. +* `listener_ip_address` - (Optional; *v3.8+*) IP address of DHCP server in network. Must match + subnet. **Only** used when `mode=NETWORK`. +* `lease_time` - (Optional; *v3.8+*; VCD `10.3.1+`) - Lease time in seconds. Minimum value is 60s + and maximum is 4294967295s (~ 49 days). +* `dns_servers` - (Optional; *v3.7+*; VCD `10.3.1+`) - The DNS server IPs to be assigned by this + DHCP service. Maximum two values. ## Pools