From b21761c17a84b9068b4aac3bcded9b1ecfa768a6 Mon Sep 17 00:00:00 2001 From: Kobi Samoray Date: Wed, 24 Jan 2024 11:25:28 +0200 Subject: [PATCH] GRE tunnel resource implementation Signed-off-by: Kobi Samoray --- nsxt/provider.go | 1 + ...ce_nsxt_policy_tier0_gateway_gre_tunnel.go | 409 ++++++++++++++++++ ...xt_policy_tier0_gateway_gre_tunnel_test.go | 148 +++++++ ...icy_tier0_gateway_gre_tunnel.html.markdown | 125 ++++++ 4 files changed, 683 insertions(+) create mode 100644 nsxt/resource_nsxt_policy_tier0_gateway_gre_tunnel.go create mode 100644 nsxt/resource_nsxt_policy_tier0_gateway_gre_tunnel_test.go create mode 100644 website/docs/r/policy_tier0_gateway_gre_tunnel.html.markdown diff --git a/nsxt/provider.go b/nsxt/provider.go index cd8ca7e96..04b5c7502 100644 --- a/nsxt/provider.go +++ b/nsxt/provider.go @@ -467,6 +467,7 @@ func Provider() *schema.Provider { "nsxt_policy_lb_passive_monitor_profile": resourceNsxtPolicyLBPassiveMonitorProfile(), "nsxt_policy_lb_tcp_monitor_profile": resourceNsxtPolicyLBTcpMonitorProfile(), "nsxt_policy_lb_udp_monitor_profile": resourceNsxtPolicyLBUdpMonitorProfile(), + "nsxt_policy_tier0_gateway_gre_tunnel": resourceNsxtPolicyTier0GatewayGRETunnel(), }, ConfigureFunc: providerConfigure, diff --git a/nsxt/resource_nsxt_policy_tier0_gateway_gre_tunnel.go b/nsxt/resource_nsxt_policy_tier0_gateway_gre_tunnel.go new file mode 100644 index 000000000..8a34c05f7 --- /dev/null +++ b/nsxt/resource_nsxt_policy_tier0_gateway_gre_tunnel.go @@ -0,0 +1,409 @@ +/* Copyright © 2024 Broadcom, Inc. All Rights Reserved. + SPDX-License-Identifier: MPL-2.0 */ + +package nsxt + +import ( + "fmt" + "log" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/vmware/vsphere-automation-sdk-go/runtime/bindings" + "github.com/vmware/vsphere-automation-sdk-go/runtime/data" + "github.com/vmware/vsphere-automation-sdk-go/runtime/protocol/client" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/infra/tier_0s/locale_services" + "github.com/vmware/vsphere-automation-sdk-go/services/nsxt/model" +) + +func resourceNsxtPolicyTier0GatewayGRETunnel() *schema.Resource { + return &schema.Resource{ + Create: resourceNsxtPolicyTier0GatewayGRETunnelCreate, + Read: resourceNsxtPolicyTier0GatewayGRETunnelRead, + Update: resourceNsxtPolicyTier0GatewayGRETunnelUpdate, + Delete: resourceNsxtPolicyTier0GatewayGRETunnelDelete, + Importer: &schema.ResourceImporter{ + State: resourceNsxtPolicyTier0GatewayGRETunnelImport, + }, + Schema: map[string]*schema.Schema{ + "nsx_id": getNsxIDSchema(), + "path": getPathSchema(), + "display_name": getDisplayNameSchema(), + "description": getDescriptionSchema(), + "revision": getRevisionSchema(), + "tag": getTagsSchema(), + "locale_service_path": { + Type: schema.TypeString, + Description: "Policy path of associated Gateway Locale Service on NSX", + Required: true, + ForceNew: true, + }, + "destination_address": { + Type: schema.TypeString, + Description: "Destination IPv4 address", + Required: true, + ValidateFunc: validation.IsIPv4Address, + }, + "enabled": { + Type: schema.TypeBool, + Description: "Enable/Disable Tunnel", + Optional: true, + Default: true, + }, + "mtu": { + Type: schema.TypeInt, + Description: "Maximum transmission unit", + Optional: true, + Default: 1476, + ValidateFunc: validation.IntAtLeast(64), + }, + "tunnel_address": { + Type: schema.TypeList, + Description: "Tunnel Address object parameter", + Required: true, + MinItems: 1, + MaxItems: 8, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "edge_path": { + Type: schema.TypeString, + Description: "Policy edge node path", + Required: true, + ValidateFunc: validatePolicyPath(), + }, + "source_address": { + Type: schema.TypeString, + Description: "IPv4 source address", + Required: true, + ValidateFunc: validateSingleIP(), + }, + "tunnel_interface_subnet": { + Type: schema.TypeList, + Description: "Interface Subnet object parameter", + Required: true, + MinItems: 1, + MaxItems: 2, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ip_addresses": { + Type: schema.TypeList, + Description: "IP addresses assigned to interface", + Required: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validateSingleIP(), + }, + }, + "prefix_len": { + Type: schema.TypeInt, + Description: "Subnet prefix length", + Required: true, + ValidateFunc: validation.IntBetween(1, 128), + }, + }, + }, + }, + }, + }, + }, + "tunnel_keepalive": { + Type: schema.TypeList, + Optional: true, + Description: "tunnel keep alive object", + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "dead_time_multiplier": { + Type: schema.TypeInt, + Description: "Dead time multiplier", + Optional: true, + ValidateFunc: validation.IntBetween(3, 5), + Default: 3, + }, + "enable_keepalive_ack": { + Type: schema.TypeBool, + Description: "Enable tunnel keep alive acknowledge", + Optional: true, + Default: true, + }, + "enabled": { + Type: schema.TypeBool, + Description: "Enable/Disable tunnel keep alive", + Optional: true, + Default: false, + }, + "keepalive_interval": { + Type: schema.TypeInt, + Description: "Keep alive interval", + ValidateFunc: validation.IntBetween(2, 120), + Optional: true, + Default: 10, + }, + }, + }, + }, + }, + } +} + +func tier0GatewayGRETunnelFromSchema(d *schema.ResourceData) (*data.StructValue, error) { + converter := bindings.NewTypeConverter() + + displayName := d.Get("display_name").(string) + description := d.Get("description").(string) + tags := getPolicyTagsFromSchema(d) + destinationAddress := d.Get("destination_address").(string) + enabled := d.Get("enabled").(bool) + mtu := int64(d.Get("mtu").(int)) + var tunnelAddresses []model.TunnelAddress + tunnelAddressList := d.Get("tunnel_address").([]interface{}) + for _, ta := range tunnelAddressList { + tunnelAddress := ta.(map[string]interface{}) + edgePath := tunnelAddress["edge_path"].(string) + sourceAddress := tunnelAddress["source_address"].(string) + var tunnelInterfaceSubnets []model.InterfaceSubnet + tunnelInterfaceSubnet := tunnelAddress["tunnel_interface_subnet"].([]interface{}) + for _, tis := range tunnelInterfaceSubnet { + t := tis.(map[string]interface{}) + ipAddresses := interfaceListToStringList(t["ip_addresses"].([]interface{})) + prefixLen := int64(t["prefix_len"].(int)) + elem := model.InterfaceSubnet{ + IpAddresses: ipAddresses, + PrefixLen: &prefixLen, + } + tunnelInterfaceSubnets = append(tunnelInterfaceSubnets, elem) + } + elem := model.TunnelAddress{ + EdgePath: &edgePath, + SourceAddress: &sourceAddress, + TunnelInterfaceSubnet: tunnelInterfaceSubnets, + } + tunnelAddresses = append(tunnelAddresses, elem) + } + var tunnelKeepalive model.TunnelKeepAlive + tunnelKeepAliveList := d.Get("tunnel_keepalive").([]interface{}) + for _, tka := range tunnelKeepAliveList { + tkaElement := tka.(map[string]interface{}) + deadTimeMultiplier := int64(tkaElement["dead_time_multiplier"].(int)) + enableKeepaliveAck := tkaElement["enable_keepalive_ack"].(bool) + tkaEnabled := tkaElement["enabled"].(bool) + keepaliveInterval := int64(tkaElement["keepalive_interval"].(int)) + + tunnelKeepalive = model.TunnelKeepAlive{ + DeadTimeMultiplier: &deadTimeMultiplier, + EnableKeepaliveAck: &enableKeepaliveAck, + Enabled: &tkaEnabled, + KeepaliveInterval: &keepaliveInterval, + } + break // Only one element is allowed. + } + + greTunnel := model.GreTunnel{ + DisplayName: &displayName, + Description: &description, + Tags: tags, + Enabled: &enabled, + Mtu: &mtu, + DestinationAddress: &destinationAddress, + TunnelAddress: tunnelAddresses, + TunnelKeepalive: &tunnelKeepalive, + ResourceType: model.GreTunnel__TYPE_IDENTIFIER, + } + dataValue, errs := converter.ConvertToVapi(greTunnel, model.GreTunnelBindingType()) + if errs != nil { + return nil, errs[0] + } else if dataValue != nil { + return dataValue.(*data.StructValue), nil + } + return nil, nil + +} + +func resourceNsxtPolicyTier0GatewayGRETunnelExists(id, localeServicePath string, connector client.Connector, isGlobalManager bool) (bool, error) { + isT0, tier0id, localeSvcID, err := parseLocaleServicePolicyPath(localeServicePath) + if err != nil { + return false, err + } + if !isT0 { + return false, fmt.Errorf("locale service path %s is not associated with a tier0 router", localeServicePath) + } + + client := locale_services.NewTunnelsClient(connector) + _, err = client.Get(tier0id, localeSvcID, id) + + if isNotFoundError(err) { + return false, nil + } + return true, nil +} + +func resourceNsxtPolicyTier0GatewayGRETunnelCreate(d *schema.ResourceData, m interface{}) error { + connector := getPolicyConnector(m) + + id := d.Get("nsx_id").(string) + if id == "" { + id = newUUID() + } + localeServicePath := d.Get("locale_service_path").(string) + isT0, tier0id, localeSvcID, err := parseLocaleServicePolicyPath(localeServicePath) + if err != nil { + return handleCreateError("GreTunnel", id, err) + } + if !isT0 { + return fmt.Errorf("locale service path %s is not associated with a tier0 router", localeServicePath) + } + client := locale_services.NewTunnelsClient(connector) + + obj, err := tier0GatewayGRETunnelFromSchema(d) + if err != nil { + return fmt.Errorf("unable to create the GRE Tunnel: %v", err) + } + err = client.Patch(tier0id, localeSvcID, id, obj) + if err != nil { + return handleCreateError("GreTunnel", id, err) + } + + d.SetId(id) + d.Set("nsx_id", id) + + return resourceNsxtPolicyTier0GatewayGRETunnelRead(d, m) +} + +func resourceNsxtPolicyTier0GatewayGRETunnelRead(d *schema.ResourceData, m interface{}) error { + connector := getPolicyConnector(m) + + id := d.Id() + if id == "" { + return fmt.Errorf("error obtaining GreTunnel ID") + } + localeServicePath := d.Get("locale_service_path").(string) + isT0, tier0id, localeSvcID, err := parseLocaleServicePolicyPath(localeServicePath) + if err != nil { + return handleCreateError("GreTunnel", id, err) + } + if !isT0 { + return fmt.Errorf("locale service path %s is not associated with a tier0 router", localeServicePath) + } + + client := locale_services.NewTunnelsClient(connector) + obj, err := client.Get(tier0id, localeSvcID, id) + if err != nil { + return handleReadError(d, "GreTunnel", id, err) + } + + converter := bindings.NewTypeConverter() + gt, errs := converter.ConvertToGolang(obj, model.GreTunnelBindingType()) + if errs != nil { + return handleReadError(d, "GreTunnel", id, errs[0]) + } + greTunnel := gt.(model.GreTunnel) + d.Set("nsx_id", id) + d.Set("path", greTunnel.Path) + d.Set("display_name", greTunnel.DisplayName) + d.Set("description", greTunnel.Description) + d.Set("revision", greTunnel.Revision) + setPolicyTagsInSchema(d, greTunnel.Tags) + d.Set("destination_address", greTunnel.DestinationAddress) + d.Set("enabled", greTunnel.Enabled) + d.Set("mtu", greTunnel.Mtu) + + var tunnelAddress []interface{} + for _, ta := range greTunnel.TunnelAddress { + elem := make(map[string]interface{}) + elem["edge_path"] = ta.EdgePath + elem["source_address"] = ta.SourceAddress + var tunnelInterfaceSubnet []interface{} + for _, tis := range ta.TunnelInterfaceSubnet { + elem := make(map[string]interface{}) + elem["ip_addresses"] = stringList2Interface(tis.IpAddresses) + elem["prefix_len"] = tis.PrefixLen + + tunnelInterfaceSubnet = append(tunnelInterfaceSubnet, elem) + } + elem["tunnel_interface_subnet"] = tunnelInterfaceSubnet + tunnelAddress = append(tunnelAddress, elem) + } + d.Set("tunnel_address", tunnelAddress) + + tunnelKeepalive := make(map[string]interface{}) + tunnelKeepalive["dead_time_multiplier"] = greTunnel.TunnelKeepalive.DeadTimeMultiplier + tunnelKeepalive["enable_keepalive_ack"] = greTunnel.TunnelKeepalive.EnableKeepaliveAck + tunnelKeepalive["enabled"] = greTunnel.TunnelKeepalive.Enabled + tunnelKeepalive["keepalive_interval"] = greTunnel.TunnelKeepalive.KeepaliveInterval + d.Set("tunnel_keepalive", []interface{}{tunnelKeepalive}) + + return nil +} + +func resourceNsxtPolicyTier0GatewayGRETunnelUpdate(d *schema.ResourceData, m interface{}) error { + connector := getPolicyConnector(m) + + id := d.Get("nsx_id").(string) + localeServicePath := d.Get("locale_service_path").(string) + isT0, tier0id, localeSvcID, err := parseLocaleServicePolicyPath(localeServicePath) + if err != nil { + return handleCreateError("GreTunnel", id, err) + } + if !isT0 { + return fmt.Errorf("locale service path %s is not associated with a tier0 router", localeServicePath) + } + client := locale_services.NewTunnelsClient(connector) + + obj, err := tier0GatewayGRETunnelFromSchema(d) + if err != nil { + return fmt.Errorf("failed to update GRE Tunnel: %v", err) + } + err = client.Patch(tier0id, localeSvcID, id, obj) + if err != nil { + return handleUpdateError("GreTunnel", id, err) + } + + d.SetId(id) + d.Set("nsx_id", id) + + return resourceNsxtPolicyTier0GatewayGRETunnelRead(d, m) +} + +func resourceNsxtPolicyTier0GatewayGRETunnelDelete(d *schema.ResourceData, m interface{}) error { + connector := getPolicyConnector(m) + + id := d.Get("nsx_id").(string) + localeServicePath := d.Get("locale_service_path").(string) + isT0, tier0id, localeSvcID, err := parseLocaleServicePolicyPath(localeServicePath) + if err != nil { + return handleCreateError("GreTunnel", id, err) + } + if !isT0 { + return fmt.Errorf("locale service path %s is not associated with a tier0 router", localeServicePath) + } + client := locale_services.NewTunnelsClient(connector) + + log.Printf("[INFO] Deleting GRE Tunnel with ID %s", id) + err = client.Delete(tier0id, localeSvcID, id) + if err != nil { + return handleDeleteError("GreTunnel", id, err) + } + + return nil +} + +func resourceNsxtPolicyTier0GatewayGRETunnelImport(d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { + // Path should be like /infra/tier-0s/test/locale-services/default/tunnels/test + importID := d.Id() + err := fmt.Errorf("expected GRE Tunnel path, got %s", importID) + s := strings.Split(importID, "/") + if len(s) < 8 { + return []*schema.ResourceData{d}, err + } + + d.SetId(s[len(s)-1]) + + s = strings.Split(importID, "/tunnels/") + if len(s) != 2 { + return []*schema.ResourceData{d}, err + } + d.Set("locale_service_path", s[0]) + + return []*schema.ResourceData{d}, nil +} diff --git a/nsxt/resource_nsxt_policy_tier0_gateway_gre_tunnel_test.go b/nsxt/resource_nsxt_policy_tier0_gateway_gre_tunnel_test.go new file mode 100644 index 000000000..cebab87e1 --- /dev/null +++ b/nsxt/resource_nsxt_policy_tier0_gateway_gre_tunnel_test.go @@ -0,0 +1,148 @@ +/* Copyright © 2024 Broadcom, Inc. All Rights Reserved. + SPDX-License-Identifier: MPL-2.0 */ + +package nsxt + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccResourceNsxtPolicyTier0GatewayGRETunnel_basic(t *testing.T) { + testResourceName := "nsxt_policy_tier0_gateway_gre_tunnel.test" + name := getAccTestResourceName() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccOnlyLocalManager(t) + testAccNSXVersion(t, "4.1.2") + }, + Providers: testAccProviders, + CheckDestroy: func(state *terraform.State) error { + return testAccNsxtNsxtPolicyTier0GatewayGRETunnelCheckDestroy(state, name) + }, + Steps: []resource.TestStep{ + { + Config: testAccNsxtNsxtPolicyTier0GatewayGRETunnelTemplate(name), + Check: resource.ComposeTestCheckFunc( + testAccNsxtNsxtPolicyTier0GatewayGRETunnelExists(testResourceName), + + resource.TestCheckResourceAttrSet(testResourceName, "nsx_id"), + resource.TestCheckResourceAttrSet(testResourceName, "path"), + resource.TestCheckResourceAttrSet(testResourceName, "revision"), + resource.TestCheckResourceAttr(testResourceName, "tag.#", "1"), + ), + }, + }, + }) +} + +func TestAccResourceNsxtPolicyTier0GatewayGRETunnel_importBasic(t *testing.T) { + name := getAccTestResourceName() + testResourceName := "nsxt_policy_tier0_gateway_gre_tunnel.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccOnlyLocalManager(t) + testAccNSXVersion(t, "4.1.2") + }, + Providers: testAccProviders, + CheckDestroy: func(state *terraform.State) error { + return testAccNsxtNsxtPolicyTier0GatewayGRETunnelCheckDestroy(state, name) + }, + Steps: []resource.TestStep{ + { + Config: testAccNsxtNsxtPolicyTier0GatewayGRETunnelTemplate(name), + }, + { + ResourceName: testResourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccResourceNsxtPolicyImportIDRetriever(testResourceName), + }, + }, + }) +} + +func testAccNsxtNsxtPolicyTier0GatewayGRETunnelExists(resourceName string) resource.TestCheckFunc { + return func(state *terraform.State) error { + + connector := getPolicyConnector(testAccProvider.Meta().(nsxtClients)) + + rs, ok := state.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("policy Tier0 Gateway GRE Tunnel resource %s not found in resources", resourceName) + } + + resourceID := rs.Primary.ID + localeServicePath := rs.Primary.Attributes["locale_service_path"] + if resourceID == "" { + return fmt.Errorf("policy Tier0 Gateway GRE Tunnel resource ID not set in resources") + } + + exists, err := resourceNsxtPolicyTier0GatewayGRETunnelExists(resourceID, localeServicePath, connector, testAccIsGlobalManager()) + if err != nil { + return err + } + if !exists { + return fmt.Errorf("policy Tier0 Gateway GRE Tunnel %s does not exist", resourceID) + } + return nil + } + +} + +func testAccNsxtNsxtPolicyTier0GatewayGRETunnelCheckDestroy(state *terraform.State, displayName string) error { + connector := getPolicyConnector(testAccProvider.Meta().(nsxtClients)) + for _, rs := range state.RootModule().Resources { + + if rs.Type != "nsxt_policy_tier0_gateway_gre_tunnel" { + continue + } + + resourceID := rs.Primary.Attributes["id"] + localeServicePath := rs.Primary.Attributes["locale_service_path"] + exists, err := resourceNsxtPolicyTier0GatewayGRETunnelExists(resourceID, localeServicePath, connector, testAccIsGlobalManager()) + if err != nil { + return err + } + if exists { + return fmt.Errorf("policy GRE Tunnel %s still exists", displayName) + } + } + return nil +} + +func testAccNsxtNsxtPolicyTier0GatewayGRETunnelTemplate(name string) string { + return testAccNsxtPolicyTier0InterfaceExternalTemplate(name, "192.168.240.10/24", "1500", "true", false) + fmt.Sprintf(` +data "nsxt_policy_gateway_locale_service" "test" { + gateway_path = nsxt_policy_tier0_gateway.test.path +} + +resource "nsxt_policy_tier0_gateway_gre_tunnel" "test" { + display_name = "%s" + description = "Acceptance test GRE tunnel" + locale_service_path = data.nsxt_policy_gateway_locale_service.test.path + destination_address = "192.168.221.221" + tunnel_address { + source_address = nsxt_policy_tier0_gateway_interface.test.ip_addresses[0] + edge_path = data.nsxt_policy_edge_node.EN.path + tunnel_interface_subnet { + ip_addresses = ["192.168.243.243"] + prefix_len = 24 + } + } + tunnel_keepalive { + enabled = false + } + tag { + scope = "scope1" + tag = "tag1" + } +}`, name) +} diff --git a/website/docs/r/policy_tier0_gateway_gre_tunnel.html.markdown b/website/docs/r/policy_tier0_gateway_gre_tunnel.html.markdown new file mode 100644 index 000000000..c359a9eb0 --- /dev/null +++ b/website/docs/r/policy_tier0_gateway_gre_tunnel.html.markdown @@ -0,0 +1,125 @@ +--- +subcategory: "Gateways and Routing" +layout: "nsxt" +page_title: "NSXT: nsxt_policy_tier0_gateway_gre_tunnel" +description: A resource to configure a GRE tunnel on Tier-0 gateway on NSX Policy manager. +--- + +# nsxt_policy_tier0_gateway_gre_tunnel + +This resource provides a method for the management of a Tier-0 gateway GRE tunnel. Note that edge cluster and an interface must be configured on Tier-0 Gateway in order to configure GRE tunnels on it. + +This resource is applicable to NSX Policy Manager. + +# Example Usage + +```hcl +data "nsxt_policy_edge_cluster" "EC" { + display_name = "EDGECLUSTER1" +} + +data "nsxt_policy_transport_zone" "test" { + display_name = "tz-vlan" +} +resource "nsxt_policy_vlan_segment" "test" { + + transport_zone_path = data.nsxt_policy_transport_zone.test.path + display_name = "test-vlan-segment" + vlan_ids = [11] + subnet { + cidr = "10.2.2.2/24" + } +} +data "nsxt_policy_edge_node" "EN" { + edge_cluster_path = data.nsxt_policy_edge_cluster.EC.path + member_index = 0 +} + +resource "nsxt_policy_tier0_gateway" "test" { + display_name = "test-gateway" + ha_mode = "ACTIVE_STANDBY" + + edge_cluster_path = data.nsxt_policy_edge_cluster.EC.path +} + +resource "nsxt_policy_tier0_gateway_interface" "test" { + display_name = "test-interface" + type = "EXTERNAL" + mtu = 1500 + gateway_path = nsxt_policy_tier0_gateway.test.path + segment_path = nsxt_policy_vlan_segment.test.path + edge_node_path = data.nsxt_policy_edge_node.EN.path + subnets = ["192.168.240.10/24"] + enable_pim = "true" +} + +data "nsxt_policy_gateway_locale_service" "test" { + gateway_path = nsxt_policy_tier0_gateway.test.path +} + +data "nsxt_policy_edge_node" "node1" { + edge_cluster_path = data.nsxt_policy_edge_cluster.EC.path + member_index = 0 +} + +resource "nsxt_policy_tier0_gateway_gre_tunnel" "test" { + display_name = "test-tunnel" + description = "Test GRE tunnel" + locale_service_path = data.nsxt_policy_gateway_locale_service.test.path + destination_address = "192.168.221.221" + tunnel_address { + source_address = nsxt_policy_tier0_gateway_interface.test.ip_addresses[0] + edge_path = data.nsxt_policy_edge_node.node1.path + tunnel_interface_subnet { + ip_addresses = ["192.168.243.243"] + prefix_len = 24 + } + } + tunnel_keepalive { + enabled = false + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `display_name` - (Required) Display name of the resource. +* `description` - (Optional) Description of the resource. +* `tag` - (Optional) A list of scope + tag pairs to associate with this resource. +* `nsx_id` - (Optional) The NSX ID of this resource. If set, this ID will be used to create the policy resource. +* `locale_service_path` - (Required) Policy path of associated Gateway Locale Service on NSX. +* `destination_address` - (Required) Destination IPv4 address. +* `enabled` - (Optional) - Enable/Disable Tunnel. Default is true. +* `mtu` - (Optional) - Maximum transmission unit. Default is 1476. +* `tunnel_address` - (Required) Tunnel Address object parameter. At least one is required, maximum is 8. + * `edge_path` - (Required) Policy edge node path. + * `source_address` - (Required) IPv4 source address. + * `tunnel_interface_subnet` - (Required) Interface Subnet object parameter. At least one is required, maximum is 2. + * `ip_addresses` - (Required) List of IP addresses assigned to interface. + * `prefix_len` - (Required) Subnet prefix length. +* `tunnel_keepalive` - (Optional) tunnel keep alive object. One is required. + * `dead_time_multiplier` - (Optional) Dead time multiplier. Default is 3. + * `enable_keepalive_ack` - (Optional) Enable tunnel keep alive acknowledge. Default is true. + * `enabled` - (Optional) Enable/Disable tunnel keep alive. Default is false. + * `keepalive_interval` - (Optional) Keep alive interval. Default is 10. + +## Attributes Reference + +In addition to arguments listed above, the following attributes are exported: + +* `id` - ID of the resource. +* `revision` - Indicates current revision number of the object as seen by NSX-T API server. This attribute can be useful for debugging. +* `path` - The NSX path of the policy resource. + + +## Importing + +An existing Tier-0 GRE tunnel can be [imported][docs-import] into this resource, via the following command: + +[docs-import]: https://www.terraform.io/cli/import +``` +terraform import nsxt_policy_tier0_gateway_gre_tunnel.test_tunnel POLICY_PATH +``` +The above command imports the Tier-0 GRE tunnel named `test_tunnel` with the policy path `POLICY_PATH`.