diff --git a/assets/terraform/examples/resources/panos_gre_tunnel/resource.tf b/assets/terraform/examples/resources/panos_gre_tunnel/resource.tf new file mode 100644 index 00000000..57494c0e --- /dev/null +++ b/assets/terraform/examples/resources/panos_gre_tunnel/resource.tf @@ -0,0 +1,64 @@ +provider "panos" { + # It is recommended to configure the provider through + # environment variables PANOS_HOSTNAME, PANOS_USERNAME, + # and PANOS_PASSWORD. +} + +resource "panos_ethernet_interface" "ethif_1" { + location = { ngfw = {} } + name = "ethernet1/2" + layer3 = { + ips = [{ + name = "4.4.4.4/24" + }] + } +} + +resource "panos_tunnel_interface" "tunnelif_1" { + location = { ngfw = {} } + name = "tunnel.2" +} + +resource "panos_gre_tunnel" "gre_full" { + location = { ngfw = {} } + name = "gre-tunnel-full" + tunnel_interface = panos_tunnel_interface.tunnelif_1.name + copy_tos = true + disabled = false + ttl = 200 + keep_alive = { + enable = true + interval = 30 + retry = 4 + hold_timer = 15 + } + local_address = { + interface = panos_ethernet_interface.ethif_1.name + ip = panos_ethernet_interface.ethif_1.layer3.ips[0].name + } + peer_address = { + ip = "5.5.5.5" + } +} + +resource "panos_ethernet_interface" "ethif_2" { + location = { ngfw = {} } + name = "ethernet1/3" + layer3 = { + ips = [{ + name = "8.8.8.8/24" + }] + } +} + +resource "panos_gre_tunnel" "gre_floating_ip" { + location = { ngfw = {} } + name = "gre-tunnel-floating-ip" + local_address = { + interface = panos_ethernet_interface.ethif_2.name + floating_ip = "6.6.6.6" + } + peer_address = { + ip = "7.7.7.7" + } +} \ No newline at end of file diff --git a/assets/terraform/test/resource_gre_tunnel_test.go b/assets/terraform/test/resource_gre_tunnel_test.go new file mode 100644 index 00000000..72c8ea28 --- /dev/null +++ b/assets/terraform/test/resource_gre_tunnel_test.go @@ -0,0 +1,399 @@ +package provider_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/config" + "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" +) + +func TestAccGreTunnel_Basic(t *testing.T) { + t.Parallel() + + nameSuffix := acctest.RandStringFromCharSet(6, acctest.CharSetAlphaNum) + prefix := fmt.Sprintf("test-acc-%s", nameSuffix) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: greTunnelBasic, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_gre_tunnel.tunnel1", + tfjsonpath.New("name"), + knownvalue.StringExact(fmt.Sprintf("%s-tunnel1", prefix)), + ), + statecheck.ExpectKnownValue( + "panos_gre_tunnel.tunnel1", + tfjsonpath.New("copy_tos"), + knownvalue.Bool(true), + ), + statecheck.ExpectKnownValue( + "panos_gre_tunnel.tunnel1", + tfjsonpath.New("disabled"), + knownvalue.Bool(false), + ), + statecheck.ExpectKnownValue( + "panos_gre_tunnel.tunnel1", + tfjsonpath.New("tunnel_interface"), + knownvalue.StringExact("tunnel.1"), + ), + statecheck.ExpectKnownValue( + "panos_gre_tunnel.tunnel1", + tfjsonpath.New("ttl"), + knownvalue.Int64Exact(128), + ), + }, + }, + }, + }) +} + +func TestAccGreTunnel_KeepAlive(t *testing.T) { + t.Parallel() + + nameSuffix := acctest.RandStringFromCharSet(6, acctest.CharSetAlphaNum) + prefix := fmt.Sprintf("test-acc-%s", nameSuffix) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: greTunnelKeepAlive, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_gre_tunnel.tunnel1", + tfjsonpath.New("name"), + knownvalue.StringExact(fmt.Sprintf("%s-tunnel1", prefix)), + ), + statecheck.ExpectKnownValue( + "panos_gre_tunnel.tunnel1", + tfjsonpath.New("keep_alive"), + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "enable": knownvalue.Bool(true), + "interval": knownvalue.Int64Exact(20), + "retry": knownvalue.Int64Exact(5), + "hold_timer": knownvalue.Int64Exact(10), + }), + ), + }, + }, + }, + }) +} + +func TestAccGreTunnel_LocalAddressIp(t *testing.T) { + t.Parallel() + + nameSuffix := acctest.RandStringFromCharSet(6, acctest.CharSetAlphaNum) + prefix := fmt.Sprintf("test-acc-%s", nameSuffix) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: greTunnelLocalAddressIp, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_gre_tunnel.tunnel1", + tfjsonpath.New("name"), + knownvalue.StringExact(fmt.Sprintf("%s-tunnel1", prefix)), + ), + statecheck.ExpectKnownValue( + "panos_gre_tunnel.tunnel1", + tfjsonpath.New("local_address"), + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "interface": knownvalue.StringExact("ethernet1/1"), + "ip": knownvalue.StringExact("1.1.1.1/24"), + "floating_ip": knownvalue.Null(), + }), + ), + }, + }, + }, + }) +} + +func TestAccGreTunnel_PeerAddress(t *testing.T) { + t.Parallel() + + nameSuffix := acctest.RandStringFromCharSet(6, acctest.CharSetAlphaNum) + prefix := fmt.Sprintf("test-acc-%s", nameSuffix) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: greTunnelPeerAddress, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_gre_tunnel.tunnel1", + tfjsonpath.New("name"), + knownvalue.StringExact(fmt.Sprintf("%s-tunnel1", prefix)), + ), + statecheck.ExpectKnownValue( + "panos_gre_tunnel.tunnel1", + tfjsonpath.New("peer_address"), + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "ip": knownvalue.StringExact("3.3.3.3"), + }), + ), + }, + }, + }, + }) +} + +func TestAccGreTunnel_Full(t *testing.T) { + t.Parallel() + + nameSuffix := acctest.RandStringFromCharSet(6, acctest.CharSetAlphaNum) + prefix := fmt.Sprintf("test-acc-%s", nameSuffix) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: greTunnelFull, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_gre_tunnel.tunnel1", + tfjsonpath.New("name"), + knownvalue.StringExact(fmt.Sprintf("%s-tunnel1", prefix)), + ), + statecheck.ExpectKnownValue( + "panos_gre_tunnel.tunnel1", + tfjsonpath.New("copy_tos"), + knownvalue.Bool(true), + ), + statecheck.ExpectKnownValue( + "panos_gre_tunnel.tunnel1", + tfjsonpath.New("disabled"), + knownvalue.Bool(false), + ), + statecheck.ExpectKnownValue( + "panos_gre_tunnel.tunnel1", + tfjsonpath.New("tunnel_interface"), + knownvalue.StringExact("tunnel.2"), + ), + statecheck.ExpectKnownValue( + "panos_gre_tunnel.tunnel1", + tfjsonpath.New("ttl"), + knownvalue.Int64Exact(200), + ), + statecheck.ExpectKnownValue( + "panos_gre_tunnel.tunnel1", + tfjsonpath.New("keep_alive"), + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "enable": knownvalue.Bool(true), + "interval": knownvalue.Int64Exact(30), + "retry": knownvalue.Int64Exact(4), + "hold_timer": knownvalue.Int64Exact(15), + }), + ), + statecheck.ExpectKnownValue( + "panos_gre_tunnel.tunnel1", + tfjsonpath.New("local_address"), + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "interface": knownvalue.StringExact("ethernet1/2"), + "ip": knownvalue.StringExact("4.4.4.4/24"), + "floating_ip": knownvalue.Null(), + }), + ), + statecheck.ExpectKnownValue( + "panos_gre_tunnel.tunnel1", + tfjsonpath.New("peer_address"), + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "ip": knownvalue.StringExact("5.5.5.5"), + }), + ), + }, + }, + }, + }) +} + +const greTunnelBasic = ` +variable "prefix" { type = string } + +locals { + template_name = format("%s-tmpl", var.prefix) +} + +resource "panos_template" "template" { + location = { panorama = {} } + name = local.template_name +} + +resource "panos_tunnel_interface" "tunnelif" { + location = { template = { name = panos_template.template.name } } + name = "tunnel.1" +} + +resource "panos_gre_tunnel" "tunnel1" { + location = { template = { name = panos_template.template.name } } + + name = format("%s-tunnel1", var.prefix) + copy_tos = true + disabled = false + tunnel_interface = panos_tunnel_interface.tunnelif.name + ttl = 128 +} +` + +const greTunnelKeepAlive = ` +variable "prefix" { type = string } + +locals { + template_name = format("%s-tmpl", var.prefix) +} + +resource "panos_template" "template" { + location = { panorama = {} } + name = local.template_name +} + +resource "panos_gre_tunnel" "tunnel1" { + location = { template = { name = panos_template.template.name } } + + name = format("%s-tunnel1", var.prefix) + keep_alive = { + enable = true + interval = 20 + retry = 5 + hold_timer = 10 + } +} +` + +const greTunnelLocalAddressIp = ` +variable "prefix" { type = string } + +locals { + template_name = format("%s-tmpl", var.prefix) +} + +resource "panos_template" "template" { + location = { panorama = {} } + name = local.template_name +} + +resource "panos_ethernet_interface" "ethif" { + location = { template = { name = panos_template.template.name } } + name = "ethernet1/1" + layer3 = { + ips = [{ + name = "1.1.1.1/24" + }] + } +} + +resource "panos_gre_tunnel" "tunnel1" { + location = { template = { name = panos_template.template.name } } + + name = format("%s-tunnel1", var.prefix) + local_address = { + interface = panos_ethernet_interface.ethif.name + ip = panos_ethernet_interface.ethif.layer3.ips.0.name + } +} +` + +const greTunnelPeerAddress = ` +variable "prefix" { type = string } + +locals { + template_name = format("%s-tmpl", var.prefix) +} + +resource "panos_template" "template" { + location = { panorama = {} } + name = local.template_name +} + +resource "panos_gre_tunnel" "tunnel1" { + location = { template = { name = panos_template.template.name } } + + name = format("%s-tunnel1", var.prefix) + peer_address = { + ip = "3.3.3.3" + } +} +` + +const greTunnelFull = ` +variable "prefix" { type = string } + +locals { + template_name = format("%s-tmpl", var.prefix) +} + +resource "panos_template" "template" { + location = { panorama = {} } + name = local.template_name +} + +resource "panos_ethernet_interface" "ethif" { + location = { template = { name = panos_template.template.name } } + name = "ethernet1/2" + layer3 = { + ips = [{ + name = "4.4.4.4/24" + }] + } +} + +resource "panos_tunnel_interface" "tunnelif" { + location = { template = { name = panos_template.template.name } } + name = "tunnel.2" +} + +resource "panos_gre_tunnel" "tunnel1" { + location = { template = { name = panos_template.template.name } } + + name = format("%s-tunnel1", var.prefix) + copy_tos = true + disabled = false + tunnel_interface = panos_tunnel_interface.tunnelif.name + ttl = 200 + keep_alive = { + enable = true + interval = 30 + retry = 4 + hold_timer = 15 + } + local_address = { + interface = panos_ethernet_interface.ethif.name + ip = "4.4.4.4/24" + } + peer_address = { + ip = "5.5.5.5" + } +} +` diff --git a/specs/network/tunnels/gre.yaml b/specs/network/tunnels/gre.yaml new file mode 100644 index 00000000..869c798d --- /dev/null +++ b/specs/network/tunnels/gre.yaml @@ -0,0 +1,297 @@ +name: gre-tunnel +terraform_provider_config: + description: GRE Tunnel + skip_resource: false + skip_datasource: false + resource_type: entry + resource_variants: + - singular + suffix: gre_tunnel + plural_suffix: '' + plural_name: '' + plural_description: '' +go_sdk_config: + skip: false + package: + - network + - tunnel + - gre +panos_xpath: + path: + - network + - tunnel + - gre + vars: [] +locations: +- name: ngfw + xpath: + path: + - config + - devices + - $ngfw_device + vars: + - name: ngfw_device + description: The NGFW device + required: false + default: localhost.localdomain + validators: [] + type: entry + description: Located in a specific NGFW device + devices: + - ngfw + validators: [] + required: false + read_only: false +- name: template + xpath: + path: + - config + - devices + - $panorama_device + - template + - $template + - config + - devices + - $ngfw_device + vars: + - name: panorama_device + description: Specific Panorama device + required: false + default: localhost.localdomain + validators: [] + type: entry + - name: template + description: Specific Panorama template + required: true + validators: [] + type: entry + - name: ngfw_device + description: The NGFW device + required: false + default: localhost.localdomain + validators: [] + type: entry + description: Located in a specific template + devices: + - panorama + validators: [] + required: false + read_only: false +- name: template-stack + xpath: + path: + - config + - devices + - $panorama_device + - template-stack + - $template_stack + - config + - devices + - $ngfw_device + vars: + - name: panorama_device + description: Specific Panorama device + required: false + default: localhost.localdomain + validators: [] + type: entry + - name: template_stack + description: Specific Panorama template stack + required: true + validators: [] + type: entry + - name: ngfw_device + description: The NGFW device + required: false + default: localhost.localdomain + validators: [] + type: entry + description: Located in a specific template stack + devices: + - panorama + validators: [] + required: false + read_only: false +entries: +- name: name + description: '' + validators: [] +imports: [] +spec: + params: + - name: copy-tos + type: bool + profiles: + - xpath: + - copy-tos + validators: [] + spec: {} + description: Copy IP TOS bits from inner packet to GRE packet + required: false + - name: disabled + type: bool + profiles: + - xpath: + - disabled + validators: [] + spec: {} + description: Disable the GRE tunnel + required: false + - name: erspan + type: bool + profiles: + - xpath: + - erspan + validators: [] + spec: {} + description: tap mode for ERSPAN + required: false + - name: keep-alive + type: object + profiles: + - xpath: + - keep-alive + validators: [] + spec: + params: + - name: enable + type: bool + profiles: + - xpath: + - enable + validators: [] + spec: {} + description: Enable tunnel monitoring on this tunnel + required: false + - name: hold-timer + type: int64 + profiles: + - xpath: + - hold-timer + validators: + - type: length + spec: + min: 1 + max: 64 + spec: + default: 5 + description: Hold timer + required: false + - name: interval + type: int64 + profiles: + - xpath: + - interval + validators: + - type: length + spec: + min: 1 + max: 50 + spec: + default: 10 + description: Interval + required: false + - name: retry + type: int64 + profiles: + - xpath: + - retry + validators: + - type: length + spec: + min: 1 + max: 64 + spec: + default: 3 + description: Retry + required: false + variants: [] + description: Monitor GRE tunnel status + required: false + - name: local-address + type: object + profiles: + - xpath: + - local-address + validators: [] + spec: + params: + - name: interface + type: string + profiles: + - xpath: + - interface + validators: [] + spec: {} + description: Interface to terminate tunnel + required: false + variants: + - name: floating-ip + type: string + profiles: + - xpath: + - floating-ip + validators: [] + spec: {} + description: Floating IP address in HA Active-Active configuration + required: false + variant_group_id: 0 + - name: ip + type: string + profiles: + - xpath: + - ip + validators: + - type: length + spec: + max: 63 + spec: {} + description: specify exact IP address if interface has multiple addresses + required: false + variant_group_id: 0 + description: Tunnel local IP configuration + required: false + - name: peer-address + type: object + profiles: + - xpath: + - peer-address + validators: [] + spec: + params: + - name: ip + type: string + profiles: + - xpath: + - ip + validators: [] + spec: {} + description: Peer IP address + required: false + variants: [] + description: Peer address + required: false + - name: ttl + type: int64 + profiles: + - xpath: + - ttl + validators: + - type: length + spec: + min: 1 + max: 255 + spec: + default: 64 + description: TTL + required: false + - name: tunnel-interface + type: string + profiles: + - xpath: + - tunnel-interface + validators: [] + spec: {} + description: to apply GRE tunnels to tunnel interface + required: false + variants: []