From a9b09c890cc4ef218cda85408c9917de062103b9 Mon Sep 17 00:00:00 2001 From: Krzysztof Klimonda Date: Mon, 11 May 2026 12:49:23 +0200 Subject: [PATCH] feat(specs): Add spec, tests and examples for panos_bfd_network_profile --- .../panos_bfd_network_profile/import.sh | 7 + .../panos_bfd_network_profile/resource.tf | 59 +++ .../test/resource_bfd_network_profile_test.go | 454 ++++++++++++++++++ .../test/resource_logical_router_test.go | 78 +++ ...e_virtual_router_static_route_ipv4_test.go | 20 +- .../test/resource_virtual_router_test.go | 254 ++++++++++ .../network/profiles/bfd-network-profile.yaml | 220 +++++++++ 7 files changed, 1089 insertions(+), 3 deletions(-) create mode 100644 assets/terraform/examples/resources/panos_bfd_network_profile/import.sh create mode 100644 assets/terraform/examples/resources/panos_bfd_network_profile/resource.tf create mode 100644 assets/terraform/test/resource_bfd_network_profile_test.go create mode 100644 specs/network/profiles/bfd-network-profile.yaml diff --git a/assets/terraform/examples/resources/panos_bfd_network_profile/import.sh b/assets/terraform/examples/resources/panos_bfd_network_profile/import.sh new file mode 100644 index 00000000..fb8e37f9 --- /dev/null +++ b/assets/terraform/examples/resources/panos_bfd_network_profile/import.sh @@ -0,0 +1,7 @@ +#!/bin/bash +# Import a BFD Network Profile from a Panorama template. +# The location must be base64-encoded JSON before passing to terraform import. + +location='{"template":{"name":"bfd-network-template","panorama_device":"localhost.localdomain","ngfw_device":"localhost.localdomain"}}' +encoded_location=$(echo -n "$location" | base64) +terraform import "panos_bfd_network_profile.active" "$encoded_location:bfd-active-fast" diff --git a/assets/terraform/examples/resources/panos_bfd_network_profile/resource.tf b/assets/terraform/examples/resources/panos_bfd_network_profile/resource.tf new file mode 100644 index 00000000..578bf9b6 --- /dev/null +++ b/assets/terraform/examples/resources/panos_bfd_network_profile/resource.tf @@ -0,0 +1,59 @@ +resource "panos_template" "example" { + location = { panorama = {} } + name = "bfd-network-template" +} + +# BFD Network Profile with active mode and custom timing parameters. +# Suitable for single-hop BFD sessions where fast failure detection is needed. +resource "panos_bfd_network_profile" "active" { + depends_on = [panos_template.example] + location = { + template = { + name = panos_template.example.name + } + } + + name = "bfd-active-fast" + + # Use active mode so this device initiates BFD control packets + mode = "active" + + # Increase the detection multiplier to allow 5 missed packets before + # declaring the session down (default is 3) + detection_multiplier = 5 + + # Require BFD control packets every 300 ms (default is 1000 ms) + min_rx_interval = 300 + min_tx_interval = 300 + + # Hold BFD sessions for 500 ms after a link event before re-negotiating + hold_time = 500 +} + +# BFD Network Profile configured for multihop sessions in passive mode. +# Multihop BFD traverses multiple IP hops (e.g., across a routed WAN) so +# a minimum accepted TTL guards against spoofed packets from closer peers. +resource "panos_bfd_network_profile" "multihop_passive" { + depends_on = [panos_template.example] + location = { + template = { + name = panos_template.example.name + } + } + + name = "bfd-multihop-passive" + + # Passive mode: wait for the remote peer to initiate BFD control packets + mode = "passive" + + detection_multiplier = 3 + min_rx_interval = 500 + min_tx_interval = 500 + + # Enable multihop and set the minimum TTL accepted on incoming BFD packets. + # A value of 200 rejects packets that have traversed more than 55 hops, + # limiting the reach of potential spoofed BFD packets. + multihop = { + min_received_ttl = 200 + } +} diff --git a/assets/terraform/test/resource_bfd_network_profile_test.go b/assets/terraform/test/resource_bfd_network_profile_test.go new file mode 100644 index 00000000..8b1ce26d --- /dev/null +++ b/assets/terraform/test/resource_bfd_network_profile_test.go @@ -0,0 +1,454 @@ +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 TestAccBfdNetworkProfile_Basic(t *testing.T) { + t.Parallel() + + nameSuffix := acctest.RandStringFromCharSet(6, acctest.CharSetAlphaNum) + prefix := fmt.Sprintf("test-acc-%s", nameSuffix) + + location := config.ObjectVariable(map[string]config.Variable{ + "template": config.ObjectVariable(map[string]config.Variable{ + "name": config.StringVariable(prefix), + }), + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: bfdNetworkProfile_Basic_Tmpl, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + "location": location, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_bfd_network_profile.example", + tfjsonpath.New("name"), + knownvalue.StringExact(prefix), + ), + statecheck.ExpectKnownValue( + "panos_bfd_network_profile.example", + tfjsonpath.New("detection_multiplier"), + knownvalue.Int64Exact(5), + ), + statecheck.ExpectKnownValue( + "panos_bfd_network_profile.example", + tfjsonpath.New("hold_time"), + knownvalue.Int64Exact(2000), + ), + statecheck.ExpectKnownValue( + "panos_bfd_network_profile.example", + tfjsonpath.New("min_rx_interval"), + knownvalue.Int64Exact(300), + ), + statecheck.ExpectKnownValue( + "panos_bfd_network_profile.example", + tfjsonpath.New("min_tx_interval"), + knownvalue.Int64Exact(400), + ), + statecheck.ExpectKnownValue( + "panos_bfd_network_profile.example", + tfjsonpath.New("mode"), + knownvalue.StringExact("active"), + ), + statecheck.ExpectKnownValue( + "panos_bfd_network_profile.example", + tfjsonpath.New("multihop"), + knownvalue.Null(), + ), + }, + }, + }, + }) +} + +const bfdNetworkProfile_Basic_Tmpl = ` +variable "prefix" { type = string } +variable "location" { type = any } + +resource "panos_template" "example" { + location = { panorama = {} } + name = var.prefix +} + +resource "panos_bfd_network_profile" "example" { + depends_on = [panos_template.example] + location = var.location + + name = var.prefix + detection_multiplier = 5 + hold_time = 2000 + min_rx_interval = 300 + min_tx_interval = 400 + mode = "active" +} +` + +func TestAccBfdNetworkProfile_Mode_Passive(t *testing.T) { + t.Parallel() + + nameSuffix := acctest.RandStringFromCharSet(6, acctest.CharSetAlphaNum) + prefix := fmt.Sprintf("test-acc-%s", nameSuffix) + + location := config.ObjectVariable(map[string]config.Variable{ + "template": config.ObjectVariable(map[string]config.Variable{ + "name": config.StringVariable(prefix), + }), + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: bfdNetworkProfile_Mode_Passive_Tmpl, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + "location": location, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_bfd_network_profile.example", + tfjsonpath.New("name"), + knownvalue.StringExact(prefix), + ), + statecheck.ExpectKnownValue( + "panos_bfd_network_profile.example", + tfjsonpath.New("mode"), + knownvalue.StringExact("passive"), + ), + }, + }, + }, + }) +} + +const bfdNetworkProfile_Mode_Passive_Tmpl = ` +variable "prefix" { type = string } +variable "location" { type = any } + +resource "panos_template" "example" { + location = { panorama = {} } + name = var.prefix +} + +resource "panos_bfd_network_profile" "example" { + depends_on = [panos_template.example] + location = var.location + + name = var.prefix + mode = "passive" +} +` + +func TestAccBfdNetworkProfile_Multihop_MinReceivedTtl(t *testing.T) { + t.Parallel() + + nameSuffix := acctest.RandStringFromCharSet(6, acctest.CharSetAlphaNum) + prefix := fmt.Sprintf("test-acc-%s", nameSuffix) + + location := config.ObjectVariable(map[string]config.Variable{ + "template": config.ObjectVariable(map[string]config.Variable{ + "name": config.StringVariable(prefix), + }), + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: bfdNetworkProfile_Multihop_MinReceivedTtl_Tmpl, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + "location": location, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_bfd_network_profile.example", + tfjsonpath.New("name"), + knownvalue.StringExact(prefix), + ), + statecheck.ExpectKnownValue( + "panos_bfd_network_profile.example", + tfjsonpath.New("multihop"), + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "min_received_ttl": knownvalue.Int64Exact(64), + }), + ), + }, + }, + }, + }) +} + +const bfdNetworkProfile_Multihop_MinReceivedTtl_Tmpl = ` +variable "prefix" { type = string } +variable "location" { type = any } + +resource "panos_template" "example" { + location = { panorama = {} } + name = var.prefix +} + +resource "panos_bfd_network_profile" "example" { + depends_on = [panos_template.example] + location = var.location + + name = var.prefix + multihop = { + min_received_ttl = 64 + } +} +` + +func TestAccBfdNetworkProfile_Multihop_WithAllParams(t *testing.T) { + t.Parallel() + + nameSuffix := acctest.RandStringFromCharSet(6, acctest.CharSetAlphaNum) + prefix := fmt.Sprintf("test-acc-%s", nameSuffix) + + location := config.ObjectVariable(map[string]config.Variable{ + "template": config.ObjectVariable(map[string]config.Variable{ + "name": config.StringVariable(prefix), + }), + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: bfdNetworkProfile_Multihop_WithAllParams_Tmpl, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + "location": location, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_bfd_network_profile.example", + tfjsonpath.New("name"), + knownvalue.StringExact(prefix), + ), + statecheck.ExpectKnownValue( + "panos_bfd_network_profile.example", + tfjsonpath.New("detection_multiplier"), + knownvalue.Int64Exact(10), + ), + statecheck.ExpectKnownValue( + "panos_bfd_network_profile.example", + tfjsonpath.New("hold_time"), + knownvalue.Int64Exact(5000), + ), + statecheck.ExpectKnownValue( + "panos_bfd_network_profile.example", + tfjsonpath.New("min_rx_interval"), + knownvalue.Int64Exact(500), + ), + statecheck.ExpectKnownValue( + "panos_bfd_network_profile.example", + tfjsonpath.New("min_tx_interval"), + knownvalue.Int64Exact(500), + ), + statecheck.ExpectKnownValue( + "panos_bfd_network_profile.example", + tfjsonpath.New("mode"), + knownvalue.StringExact("passive"), + ), + statecheck.ExpectKnownValue( + "panos_bfd_network_profile.example", + tfjsonpath.New("multihop"), + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "min_received_ttl": knownvalue.Int64Exact(128), + }), + ), + }, + }, + }, + }) +} + +const bfdNetworkProfile_Multihop_WithAllParams_Tmpl = ` +variable "prefix" { type = string } +variable "location" { type = any } + +resource "panos_template" "example" { + location = { panorama = {} } + name = var.prefix +} + +resource "panos_bfd_network_profile" "example" { + depends_on = [panos_template.example] + location = var.location + + name = var.prefix + detection_multiplier = 10 + hold_time = 5000 + min_rx_interval = 500 + min_tx_interval = 500 + mode = "passive" + multihop = { + min_received_ttl = 128 + } +} +` + +func TestAccBfdNetworkProfile_Defaults(t *testing.T) { + t.Parallel() + + nameSuffix := acctest.RandStringFromCharSet(6, acctest.CharSetAlphaNum) + prefix := fmt.Sprintf("test-acc-%s", nameSuffix) + + location := config.ObjectVariable(map[string]config.Variable{ + "template": config.ObjectVariable(map[string]config.Variable{ + "name": config.StringVariable(prefix), + }), + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: bfdNetworkProfile_Defaults_Tmpl, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + "location": location, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_bfd_network_profile.example", + tfjsonpath.New("name"), + knownvalue.StringExact(prefix), + ), + statecheck.ExpectKnownValue( + "panos_bfd_network_profile.example", + tfjsonpath.New("detection_multiplier"), + knownvalue.Int64Exact(3), + ), + statecheck.ExpectKnownValue( + "panos_bfd_network_profile.example", + tfjsonpath.New("hold_time"), + knownvalue.Int64Exact(0), + ), + statecheck.ExpectKnownValue( + "panos_bfd_network_profile.example", + tfjsonpath.New("min_rx_interval"), + knownvalue.Int64Exact(1000), + ), + statecheck.ExpectKnownValue( + "panos_bfd_network_profile.example", + tfjsonpath.New("min_tx_interval"), + knownvalue.Int64Exact(1000), + ), + statecheck.ExpectKnownValue( + "panos_bfd_network_profile.example", + tfjsonpath.New("mode"), + knownvalue.StringExact("active"), + ), + statecheck.ExpectKnownValue( + "panos_bfd_network_profile.example", + tfjsonpath.New("multihop"), + knownvalue.Null(), + ), + }, + }, + }, + }) +} + +const bfdNetworkProfile_Defaults_Tmpl = ` +variable "prefix" { type = string } +variable "location" { type = any } + +resource "panos_template" "example" { + location = { panorama = {} } + name = var.prefix +} + +resource "panos_bfd_network_profile" "example" { + depends_on = [panos_template.example] + location = var.location + + name = var.prefix +} +` + +func TestAccBfdNetworkProfile_TemplateStack(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: bfdNetworkProfile_TemplateStack_Tmpl, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_bfd_network_profile.example", + tfjsonpath.New("name"), + knownvalue.StringExact(fmt.Sprintf("%s-profile", prefix)), + ), + statecheck.ExpectKnownValue( + "panos_bfd_network_profile.example", + tfjsonpath.New("detection_multiplier"), + knownvalue.Int64Exact(4), + ), + statecheck.ExpectKnownValue( + "panos_bfd_network_profile.example", + tfjsonpath.New("mode"), + knownvalue.StringExact("active"), + ), + statecheck.ExpectKnownValue( + "panos_bfd_network_profile.example", + tfjsonpath.New("location").AtMapKey("template_stack").AtMapKey("name"), + knownvalue.StringExact(fmt.Sprintf("%s-stack", prefix)), + ), + }, + }, + }, + }) +} + +const bfdNetworkProfile_TemplateStack_Tmpl = ` +variable "prefix" { type = string } + +resource "panos_template" "example" { + location = { panorama = {} } + name = var.prefix +} + +resource "panos_template_stack" "example" { + location = { panorama = {} } + name = "${var.prefix}-stack" + templates = [panos_template.example.name] +} + +resource "panos_bfd_network_profile" "example" { + location = { template_stack = { name = panos_template_stack.example.name } } + + name = "${var.prefix}-profile" + detection_multiplier = 4 + mode = "active" +} +` diff --git a/assets/terraform/test/resource_logical_router_test.go b/assets/terraform/test/resource_logical_router_test.go index 30319615..8346123d 100644 --- a/assets/terraform/test/resource_logical_router_test.go +++ b/assets/terraform/test/resource_logical_router_test.go @@ -7,6 +7,9 @@ import ( "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" ) // TestAccPanosLogicalRouter_Basic is a comprehensive test covering: @@ -1227,3 +1230,78 @@ resource "panos_logical_router" "example" { func TestAccPanosLogicalRouter_Bgp_PeerAddress_Fqdn(t *testing.T) { t.Skip("Skipping test - BGP peer-groups require address-family profiles which are not available in this test") } + +// TestAccPanosLogicalRouter_Bgp_GlobalBfd tests BGP global BFD profile reference +// in a logical router VRF, using a panos_bfd_routing_profile resource. +func TestAccPanosLogicalRouter_Bgp_GlobalBfd(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: panosLogicalRouterBgpGlobalBfd, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_logical_router.test", + tfjsonpath.New("vrf").AtSliceIndex(0).AtMapKey("bgp").AtMapKey("global_bfd").AtMapKey("profile"), + knownvalue.StringExact(fmt.Sprintf("%s-bfd", prefix)), + ), + statecheck.ExpectKnownValue( + "panos_logical_router.test", + tfjsonpath.New("vrf").AtSliceIndex(0).AtMapKey("bgp").AtMapKey("enable"), + knownvalue.Bool(true), + ), + }, + }, + }, + }) +} + +const panosLogicalRouterBgpGlobalBfd = ` +variable "prefix" { type = string } + +resource "panos_template" "test" { + location = { panorama = {} } + name = format("%s-tmpl", var.prefix) +} + +resource "panos_bfd_routing_profile" "test" { + depends_on = [panos_template.test] + location = { + template = { + name = panos_template.test.name + } + } + + name = format("%s-bfd", var.prefix) + mode = "active" + detection_multiplier = 5 +} + +resource "panos_logical_router" "test" { + location = { template = { name = panos_template.test.name } } + name = format("%s-router", var.prefix) + + vrf = [{ + name = "default" + + bgp = { + enable = true + router_id = "10.0.0.1" + local_as = "65001" + + global_bfd = { + profile = panos_bfd_routing_profile.test.name + } + } + }] +} +` diff --git a/assets/terraform/test/resource_virtual_router_static_route_ipv4_test.go b/assets/terraform/test/resource_virtual_router_static_route_ipv4_test.go index 0d47d49f..10d4b689 100644 --- a/assets/terraform/test/resource_virtual_router_static_route_ipv4_test.go +++ b/assets/terraform/test/resource_virtual_router_static_route_ipv4_test.go @@ -89,6 +89,11 @@ func TestAccVirtualRouterStaticRouteIpv4(t *testing.T) { }), }), ), + statecheck.ExpectKnownValue( + "panos_virtual_router_static_route_ipv4.example", + tfjsonpath.New("bfd").AtMapKey("profile"), + knownvalue.StringExact(fmt.Sprintf("%s-bfd", prefix)), + ), statecheck.ExpectKnownValue( "panos_virtual_router_static_route_ipv4.example", tfjsonpath.New("route_table"), @@ -154,6 +159,15 @@ resource "panos_virtual_router" "example2" { name = format("%s-vr2", var.prefix) } +resource "panos_bfd_network_profile" "example" { + depends_on = [panos_template.example] + location = var.location + + name = format("%s-bfd", var.prefix) + mode = "active" + detection_multiplier = 3 +} + resource "panos_virtual_router_static_route_ipv4" "example" { location = var.location @@ -166,9 +180,9 @@ resource "panos_virtual_router_static_route_ipv4" "example" { interface = panos_ethernet_interface.example.name metric = 100 - #bfd = { - # profile = "BFD-profile" - #} + bfd = { + profile = panos_bfd_network_profile.example.name + } nexthop = { ip_address = "192.168.1.254" diff --git a/assets/terraform/test/resource_virtual_router_test.go b/assets/terraform/test/resource_virtual_router_test.go index 4e87a476..ea453745 100644 --- a/assets/terraform/test/resource_virtual_router_test.go +++ b/assets/terraform/test/resource_virtual_router_test.go @@ -4307,3 +4307,257 @@ resource "panos_virtual_router" "test" { name = var.router_name } ` + +// BFD Global Profile Tests + +func TestAccPanosVirtualRouter_Bgp_GlobalBfd(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: testAccVirtualRouterBgpGlobalBfd, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_virtual_router.test", + tfjsonpath.New("protocol").AtMapKey("bgp").AtMapKey("enable"), + knownvalue.Bool(true), + ), + statecheck.ExpectKnownValue( + "panos_virtual_router.test", + tfjsonpath.New("protocol").AtMapKey("bgp").AtMapKey("global_bfd").AtMapKey("profile"), + knownvalue.StringExact(fmt.Sprintf("%s-bfd", prefix)), + ), + }, + }, + }, + }) +} + +const testAccVirtualRouterBgpGlobalBfd = ` +variable "prefix" { type = string } + +resource "panos_template" "test" { + location = { panorama = {} } + name = var.prefix +} + +resource "panos_bfd_network_profile" "test" { + depends_on = [panos_template.test] + location = { + template = { + name = panos_template.test.name + } + } + + name = "${var.prefix}-bfd" + mode = "active" + detection_multiplier = 5 +} + +resource "panos_virtual_router" "test" { + location = { + template = { + name = panos_template.test.name + } + } + + name = var.prefix + + protocol = { + bgp = { + enable = true + router_id = "10.0.20.1" + local_as = "65020" + global_bfd = { + profile = panos_bfd_network_profile.test.name + } + } + } +} +` + +func TestAccPanosVirtualRouter_Ospf_GlobalBfd(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: testAccVirtualRouterOspfGlobalBfd, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_virtual_router.test", + tfjsonpath.New("protocol").AtMapKey("ospf").AtMapKey("global_bfd").AtMapKey("profile"), + knownvalue.StringExact(fmt.Sprintf("%s-bfd", prefix)), + ), + statecheck.ExpectKnownValue( + "panos_virtual_router.test", + tfjsonpath.New("protocol").AtMapKey("ospf").AtMapKey("area").AtSliceIndex(0).AtMapKey("interface").AtSliceIndex(0).AtMapKey("bfd").AtMapKey("profile"), + knownvalue.StringExact("Inherit-vr-global-setting"), + ), + }, + }, + }, + }) +} + +const testAccVirtualRouterOspfGlobalBfd = ` +variable "prefix" { type = string } + +resource "panos_template" "test" { + location = { panorama = {} } + name = var.prefix +} + +resource "panos_ethernet_interface" "test" { + location = { + template = { + vsys = "vsys1" + name = panos_template.test.name + } + } + + name = "ethernet1/9" + + layer3 = { + mtu = 1500 + ips = [{ name = "10.0.9.1/24" }] + } +} + +resource "panos_bfd_network_profile" "test" { + depends_on = [panos_template.test] + location = { + template = { + name = panos_template.test.name + } + } + + name = "${var.prefix}-bfd" + mode = "active" + detection_multiplier = 5 +} + +resource "panos_virtual_router" "test" { + location = { + template = { + name = panos_template.test.name + } + } + + name = var.prefix + + interfaces = [panos_ethernet_interface.test.name] + + protocol = { + ospf = { + enable = true + router_id = "10.0.1.9" + global_bfd = { + profile = panos_bfd_network_profile.test.name + } + area = [ + { + name = "0.0.0.0" + type = { + normal = {} + } + interface = [ + { + name = "ethernet1/9" + enable = true + bfd = { + profile = "Inherit-vr-global-setting" + } + } + ] + } + ] + } + } +} +` + +func TestAccPanosVirtualRouter_Rip_GlobalBfd(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: testAccVirtualRouterRipGlobalBfd, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_virtual_router.test", + tfjsonpath.New("protocol").AtMapKey("rip").AtMapKey("global_bfd").AtMapKey("profile"), + knownvalue.StringExact(fmt.Sprintf("%s-bfd", prefix)), + ), + }, + }, + }, + }) +} + +const testAccVirtualRouterRipGlobalBfd = ` +variable "prefix" { type = string } + +resource "panos_template" "test" { + location = { panorama = {} } + name = var.prefix +} + +resource "panos_bfd_network_profile" "test" { + depends_on = [panos_template.test] + location = { + template = { + name = panos_template.test.name + } + } + + name = "${var.prefix}-bfd" + mode = "active" + detection_multiplier = 5 +} + +resource "panos_virtual_router" "test" { + location = { + template = { + name = panos_template.test.name + } + } + + name = var.prefix + + protocol = { + rip = { + enable = true + global_bfd = { + profile = panos_bfd_network_profile.test.name + } + } + } +} +` diff --git a/specs/network/profiles/bfd-network-profile.yaml b/specs/network/profiles/bfd-network-profile.yaml new file mode 100644 index 00000000..5f57926f --- /dev/null +++ b/specs/network/profiles/bfd-network-profile.yaml @@ -0,0 +1,220 @@ +name: bfd-network-profile +terraform_provider_config: + description: BFD Network Profile + skip_resource: false + skip_datasource: false + resource_type: entry + resource_variants: + - singular + suffix: bfd_network_profile + plural_suffix: '' + plural_name: '' + plural_description: '' + custom_validation: false +go_sdk_config: + skip: false + package: + - network + - profiles + - bfd +panos_xpath: + path: + - network + - profiles + - bfd-profile + 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: [] +spec: + params: + - name: detection-multiplier + type: int64 + profiles: + - xpath: + - detection-multiplier + validators: + - type: length + spec: + min: 2 + max: 255 + spec: + default: 3 + description: multiplier sent to remote system + required: false + - name: hold-time + type: int64 + profiles: + - xpath: + - hold-time + validators: + - type: length + spec: + min: 0 + max: 120000 + spec: + default: 0 + description: delay transmission and reception of control packets in ms + required: false + - name: min-rx-interval + type: int64 + profiles: + - xpath: + - min-rx-interval + validators: + - type: length + spec: + min: 50 + max: 10000 + spec: + default: 1000 + description: required minimum rx interval in ms + required: false + - name: min-tx-interval + type: int64 + profiles: + - xpath: + - min-tx-interval + validators: + - type: length + spec: + min: 50 + max: 10000 + spec: + default: 1000 + description: desired minimum tx interval in ms + required: false + - name: mode + type: enum + profiles: + - xpath: + - mode + validators: + - type: values + spec: + values: + - active + - passive + spec: + default: active + values: + - value: active + - value: passive + description: BFD operation mode + required: false + - name: multihop + type: object + profiles: + - xpath: + - multihop + validators: [] + spec: + params: + - name: min-received-ttl + type: int64 + profiles: + - xpath: + - min-received-ttl + validators: + - type: length + spec: + min: 1 + max: 254 + spec: {} + description: minimum accepted ttl on received BFD packet + required: false + variants: [] + description: enable multihop + required: false + variants: []