diff --git a/assets/terraform/examples/resources/panos_qos_policy/import.sh b/assets/terraform/examples/resources/panos_qos_policy/import.sh new file mode 100644 index 00000000..7bcd68d0 --- /dev/null +++ b/assets/terraform/examples/resources/panos_qos_policy/import.sh @@ -0,0 +1,16 @@ +# The entire QoS policy can be imported by providing the following base64 encoded object as the ID +# { +# location = { +# device_group = { +# name = "example-device-group" +# rulebase = "pre-rulebase" +# panorama_device = "localhost.localdomain" +# } +# } +# +# +# names = [ +# "qos-rule-1", <- the first rule in the policy +# ] +# } +terraform import panos_qos_policy.example $(echo '{"location":{"device_group":{"name":"example-device-group","panorama_device":"localhost.localdomain","rulebase":"pre-rulebase"}},"names":["qos-rule-1"]}' | base64) diff --git a/assets/terraform/examples/resources/panos_qos_policy/resource.tf b/assets/terraform/examples/resources/panos_qos_policy/resource.tf new file mode 100644 index 00000000..1c5c05c1 --- /dev/null +++ b/assets/terraform/examples/resources/panos_qos_policy/resource.tf @@ -0,0 +1,59 @@ +# Manages the entire QoS policy +resource "panos_qos_policy" "example" { + location = { + device_group = { + name = panos_device_group.example.name + } + } + + rules = [ + { + name = "qos-rule-1" + description = "QoS rule for high priority traffic" + + source_zones = ["trust"] + source_addresses = ["any"] + destination_zones = ["untrust"] + destination_addresses = ["any"] + applications = ["ssl"] + services = ["application-default"] + + action = { + class = "4" + } + + dscp_tos = { + codepoints = [ + { + name = "ef-marking" + ef = { + codepoint = "ef" + } + } + ] + } + }, + { + name = "qos-rule-2" + + source_zones = ["any"] + source_addresses = ["any"] + destination_zones = ["any"] + destination_addresses = ["any"] + applications = ["any"] + services = ["any"] + + action = { + class = "1" + } + } + ] +} + +resource "panos_device_group" "example" { + location = { + panorama = {} + } + + name = "example-device-group" +} diff --git a/assets/terraform/examples/resources/panos_qos_policy_rules/import.sh b/assets/terraform/examples/resources/panos_qos_policy_rules/import.sh new file mode 100644 index 00000000..1ac73028 --- /dev/null +++ b/assets/terraform/examples/resources/panos_qos_policy_rules/import.sh @@ -0,0 +1,18 @@ +# A set of QoS rules can be imported by providing the following base64 encoded object as the ID +# { +# location = { +# device_group = { +# name = "example-device-group" +# rulebase = "pre-rulebase" +# panorama_device = "localhost.localdomain" +# } +# } +# +# position = { where = "after", directly = true, pivot = "existing-rule" } +# +# names = [ +# "qos-rule-8", +# "qos-rule-9" +# ] +# } +terraform import panos_qos_policy_rules.example $(echo '{"location":{"device_group":{"name":"example-device-group","panorama_device":"localhost.localdomain","rulebase":"pre-rulebase"}},"names":["qos-rule-8","qos-rule-9"],"position":{"directly":true,"pivot":"existing-rule","where":"after"}}' | base64) diff --git a/assets/terraform/examples/resources/panos_qos_policy_rules/resource.tf b/assets/terraform/examples/resources/panos_qos_policy_rules/resource.tf new file mode 100644 index 00000000..ae912e87 --- /dev/null +++ b/assets/terraform/examples/resources/panos_qos_policy_rules/resource.tf @@ -0,0 +1,90 @@ +# Manage a group of QoS policy rules. + +## Place the rule group at the top +resource "panos_qos_policy_rules" "example-1" { + location = { + device_group = { + name = panos_device_group.example.name + } + } + + position = { + where = "first" # first, last, after, before + } + + rules = [ + { + name = "qos-rule-1" + description = "High priority VoIP traffic" + + source_zones = ["trust"] + source_addresses = ["any"] + destination_zones = ["untrust"] + destination_addresses = ["any"] + applications = ["sip", "h323"] + services = ["application-default"] + + action = { + class = "7" + } + + dscp_tos = { + codepoints = [ + { + name = "ef-marking" + ef = { + codepoint = "ef" + } + } + ] + } + } + ] +} + +## Place the rule group directly after an existing rule +resource "panos_qos_policy_rules" "example-2" { + location = { + device_group = { + name = panos_device_group.example.name + } + } + + position = { where = "after", directly = true, pivot = "existing-rule" } + + rules = [for k in ["web", "database", "default"] : + { + name = "qos-${k}" + + source_zones = ["any"] + source_addresses = ["any"] + destination_zones = ["any"] + destination_addresses = ["any"] + applications = ["any"] + services = ["any"] + + action = { + class = k == "web" ? "5" : k == "database" ? "4" : "1" + } + + dscp_tos = { + codepoints = [ + { + name = "${k}-codepoint" + af = { + codepoint = k == "web" ? "af21" : k == "database" ? "af31" : "af11" + } + } + ] + } + } + ] +} + +resource "panos_device_group" "example" { + location = { + panorama = {} + } + + name = "example-device-group" +} diff --git a/assets/terraform/test/resource_firewall_device_test.go b/assets/terraform/test/resource_firewall_device_test.go new file mode 100644 index 00000000..53e6d92d --- /dev/null +++ b/assets/terraform/test/resource_firewall_device_test.go @@ -0,0 +1,165 @@ +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 TestAccFirewallDevice_Basic(t *testing.T) { + t.Parallel() + + // Generate a serial number matching PAN-OS format: 00 + 13 digits + suffix := acctest.RandStringFromCharSet(13, "0123456789") + serialNumber := fmt.Sprintf("00%s", suffix) + + location := config.ObjectVariable(map[string]config.Variable{ + "panorama": config.ObjectVariable(map[string]config.Variable{}), + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: firewallDevice_Basic_Tmpl, + ConfigVariables: map[string]config.Variable{ + "serial_number": config.StringVariable(serialNumber), + "location": location, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_firewall_device.example", + tfjsonpath.New("name"), + knownvalue.StringExact(serialNumber), + ), + statecheck.ExpectKnownValue( + "panos_firewall_device.example", + tfjsonpath.New("auto_push"), + knownvalue.Bool(true), + ), + statecheck.ExpectKnownValue( + "panos_firewall_device.example", + tfjsonpath.New("disable_config_backup"), + knownvalue.Bool(false), + ), + statecheck.ExpectKnownValue( + "panos_firewall_device.example", + tfjsonpath.New("hostname"), + knownvalue.StringExact("fw.example.com"), + ), + statecheck.ExpectKnownValue( + "panos_firewall_device.example", + tfjsonpath.New("ip"), + knownvalue.StringExact("192.0.2.1"), + ), + statecheck.ExpectKnownValue( + "panos_firewall_device.example", + tfjsonpath.New("to_sw_version"), + knownvalue.StringExact("11.0.0"), + ), + statecheck.ExpectKnownValue( + "panos_firewall_device.example", + tfjsonpath.New("vsys"), + knownvalue.Null(), + ), + }, + }, + }, + }) +} + +const firewallDevice_Basic_Tmpl = ` +variable "serial_number" { type = string } +variable "location" { type = any } + +resource "panos_firewall_device" "example" { + location = var.location + name = var.serial_number + + auto_push = true + disable_config_backup = false + hostname = "fw.example.com" + ip = "192.0.2.1" + to_sw_version = "11.0.0" +} +` + +func TestAccFirewallDevice_Vsys(t *testing.T) { + t.Parallel() + + // Generate a serial number matching PAN-OS format: 00 + 13 digits + suffix := acctest.RandStringFromCharSet(13, "0123456789") + serialNumber := fmt.Sprintf("00%s", suffix) + + location := config.ObjectVariable(map[string]config.Variable{ + "panorama": config.ObjectVariable(map[string]config.Variable{}), + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: firewallDevice_Vsys_Tmpl, + ConfigVariables: map[string]config.Variable{ + "serial_number": config.StringVariable(serialNumber), + "location": location, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_firewall_device.example", + tfjsonpath.New("name"), + knownvalue.StringExact(serialNumber), + ), + statecheck.ExpectKnownValue( + "panos_firewall_device.example", + tfjsonpath.New("vsys"), + knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "name": knownvalue.StringExact("vsys1"), + "tags": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.StringExact("tag1"), + knownvalue.StringExact("tag2"), + }), + }), + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "name": knownvalue.StringExact("vsys2"), + "tags": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.StringExact("tag3"), + }), + }), + }), + ), + }, + }, + }, + }) +} + +const firewallDevice_Vsys_Tmpl = ` +variable "serial_number" { type = string } +variable "location" { type = any } + +resource "panos_firewall_device" "example" { + location = var.location + name = var.serial_number + + vsys = [ + { + name = "vsys1" + tags = ["tag1", "tag2"] + }, + { + name = "vsys2" + tags = ["tag3"] + } + ] +} +` diff --git a/assets/terraform/test/resource_qos_policy_test.go b/assets/terraform/test/resource_qos_policy_test.go new file mode 100644 index 00000000..2a375c2c --- /dev/null +++ b/assets/terraform/test/resource_qos_policy_test.go @@ -0,0 +1,1260 @@ +package provider_test + +import ( + "context" + "fmt" + "testing" + + "github.com/PaloAltoNetworks/pango/policies/rules/qos" + "github.com/PaloAltoNetworks/pango/util" + "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/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" +) + +const qosPolicy_Basic_Tmpl = ` +variable "prefix" { type = string } +variable "location" { type = any } + +resource "panos_template" "example" { + location = { panorama = {} } + name = var.prefix +} + +resource "panos_device_group" "example" { + location = { panorama = {} } + name = format("%s-dg", var.prefix) + templates = [panos_template.example.name] +} + +resource "panos_qos_policy" "example" { + depends_on = [panos_device_group.example] + location = var.location + + rules = [{ + name = format("%s-rule", var.prefix) + description = "QoS policy test rule" + + source_zones = ["any"] + source_addresses = ["any"] + source_users = ["any"] + negate_source = false + + destination_zones = ["any"] + destination_addresses = ["any"] + negate_destination = false + + applications = ["any"] + services = ["any"] + + action = { + class = "3" + } + + disabled = false + }] +} +` + +func TestAccQosPolicy_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{ + "device_group": config.ObjectVariable(map[string]config.Variable{ + "name": config.StringVariable(fmt.Sprintf("%s-dg", prefix)), + "rulebase": config.StringVariable("pre-rulebase"), + }), + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: qosPolicy_Basic_Tmpl, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + "location": location, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_qos_policy.example", + tfjsonpath.New("rules").AtSliceIndex(0), + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "name": knownvalue.StringExact(fmt.Sprintf("%s-rule", prefix)), + "description": knownvalue.StringExact("QoS policy test rule"), + "source_zones": knownvalue.SetExact([]knownvalue.Check{knownvalue.StringExact("any")}), + "source_addresses": knownvalue.SetExact([]knownvalue.Check{knownvalue.StringExact("any")}), + "source_users": knownvalue.SetExact([]knownvalue.Check{knownvalue.StringExact("any")}), + "negate_source": knownvalue.Bool(false), + "destination_zones": knownvalue.SetExact([]knownvalue.Check{knownvalue.StringExact("any")}), + "destination_addresses": knownvalue.SetExact([]knownvalue.Check{knownvalue.StringExact("any")}), + "negate_destination": knownvalue.Bool(false), + "applications": knownvalue.SetExact([]knownvalue.Check{knownvalue.StringExact("any")}), + "services": knownvalue.SetExact([]knownvalue.Check{knownvalue.StringExact("any")}), + "action": knownvalue.ObjectExact(map[string]knownvalue.Check{"class": knownvalue.StringExact("3")}), + "disabled": knownvalue.Bool(false), + "category": knownvalue.Null(), + "destination_hip": knownvalue.Null(), + "dscp_tos": knownvalue.Null(), + "group_tag": knownvalue.Null(), + "schedule": knownvalue.Null(), + "source_hip": knownvalue.Null(), + "tag": knownvalue.Null(), + "target": knownvalue.Null(), + }), + ), + }, + }, + }, + }) +} + +const qosPolicy_DscpTos_Any_Tmpl = ` +variable "prefix" { type = string } +variable "location" { type = any } + +resource "panos_template" "example" { + location = { panorama = {} } + name = var.prefix +} + +resource "panos_device_group" "example" { + location = { panorama = {} } + name = format("%s-dg", var.prefix) + templates = [panos_template.example.name] +} + +resource "panos_qos_policy" "example" { + depends_on = [panos_device_group.example] + location = var.location + + rules = [{ + name = format("%s-rule", var.prefix) + + source_zones = ["any"] + source_addresses = ["any"] + destination_zones = ["any"] + destination_addresses = ["any"] + applications = ["any"] + services = ["any"] + + action = { + class = "3" + } + + dscp_tos = { + any = {} + } + }] +} +` + +func TestAccQosPolicy_DscpTos_Any(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{ + "device_group": config.ObjectVariable(map[string]config.Variable{ + "name": config.StringVariable(fmt.Sprintf("%s-dg", prefix)), + "rulebase": config.StringVariable("pre-rulebase"), + }), + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: qosPolicy_DscpTos_Any_Tmpl, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + "location": location, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_qos_policy.example", + tfjsonpath.New("rules").AtSliceIndex(0).AtMapKey("dscp_tos"), + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "any": knownvalue.ObjectExact(map[string]knownvalue.Check{}), + "codepoints": knownvalue.Null(), + }), + ), + }, + }, + }, + }) +} + +const qosPolicy_DscpTos_Codepoints_Ef_Tmpl = ` +variable "prefix" { type = string } +variable "location" { type = any } + +resource "panos_template" "example" { + location = { panorama = {} } + name = var.prefix +} + +resource "panos_device_group" "example" { + location = { panorama = {} } + name = format("%s-dg", var.prefix) + templates = [panos_template.example.name] +} + +resource "panos_qos_policy" "example" { + depends_on = [panos_device_group.example] + location = var.location + + rules = [{ + name = format("%s-rule", var.prefix) + + source_zones = ["any"] + source_addresses = ["any"] + destination_zones = ["any"] + destination_addresses = ["any"] + applications = ["any"] + services = ["any"] + + action = { + class = "3" + } + + dscp_tos = { + codepoints = [ + { + name = "ef-codepoint" + ef = { + codepoint = "ef" + } + } + ] + } + }] +} +` + +func TestAccQosPolicy_DscpTos_Codepoints_Ef(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{ + "device_group": config.ObjectVariable(map[string]config.Variable{ + "name": config.StringVariable(fmt.Sprintf("%s-dg", prefix)), + "rulebase": config.StringVariable("pre-rulebase"), + }), + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: qosPolicy_DscpTos_Codepoints_Ef_Tmpl, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + "location": location, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_qos_policy.example", + tfjsonpath.New("rules").AtSliceIndex(0).AtMapKey("dscp_tos").AtMapKey("codepoints").AtSliceIndex(0), + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "name": knownvalue.StringExact("ef-codepoint"), + "ef": knownvalue.ObjectExact(map[string]knownvalue.Check{"codepoint": knownvalue.StringExact("ef")}), + "af": knownvalue.Null(), + "cs": knownvalue.Null(), + "tos": knownvalue.Null(), + "custom": knownvalue.Null(), + }), + ), + }, + }, + }, + }) +} + +const qosPolicy_DscpTos_Codepoints_Af_Tmpl = ` +variable "prefix" { type = string } +variable "location" { type = any } + +resource "panos_template" "example" { + location = { panorama = {} } + name = var.prefix +} + +resource "panos_device_group" "example" { + location = { panorama = {} } + name = format("%s-dg", var.prefix) + templates = [panos_template.example.name] +} + +resource "panos_qos_policy" "example" { + depends_on = [panos_device_group.example] + location = var.location + + rules = [{ + name = format("%s-rule", var.prefix) + + source_zones = ["any"] + source_addresses = ["any"] + destination_zones = ["any"] + destination_addresses = ["any"] + applications = ["any"] + services = ["any"] + + action = { + class = "3" + } + + dscp_tos = { + codepoints = [ + { + name = "af-codepoint" + af = { + codepoint = "af11" + } + } + ] + } + }] +} +` + +func TestAccQosPolicy_DscpTos_Codepoints_Af(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{ + "device_group": config.ObjectVariable(map[string]config.Variable{ + "name": config.StringVariable(fmt.Sprintf("%s-dg", prefix)), + "rulebase": config.StringVariable("pre-rulebase"), + }), + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: qosPolicy_DscpTos_Codepoints_Af_Tmpl, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + "location": location, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_qos_policy.example", + tfjsonpath.New("rules").AtSliceIndex(0).AtMapKey("dscp_tos").AtMapKey("codepoints").AtSliceIndex(0), + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "name": knownvalue.StringExact("af-codepoint"), + "af": knownvalue.ObjectExact(map[string]knownvalue.Check{"codepoint": knownvalue.StringExact("af11")}), + "ef": knownvalue.Null(), + "cs": knownvalue.Null(), + "tos": knownvalue.Null(), + "custom": knownvalue.Null(), + }), + ), + }, + }, + }, + }) +} + +const qosPolicy_DscpTos_Codepoints_Multiple_Tmpl = ` +variable "prefix" { type = string } +variable "location" { type = any } + +resource "panos_template" "example" { + location = { panorama = {} } + name = var.prefix +} + +resource "panos_device_group" "example" { + location = { panorama = {} } + name = format("%s-dg", var.prefix) + templates = [panos_template.example.name] +} + +resource "panos_qos_policy" "example" { + depends_on = [panos_device_group.example] + location = var.location + + rules = [{ + name = format("%s-rule", var.prefix) + + source_zones = ["any"] + source_addresses = ["any"] + destination_zones = ["any"] + destination_addresses = ["any"] + applications = ["any"] + services = ["any"] + + action = { + class = "3" + } + + dscp_tos = { + codepoints = [ + { + name = "ef-codepoint" + ef = { + codepoint = "ef" + } + }, + { + name = "af-codepoint" + af = { + codepoint = "af11" + } + }, + { + name = "cs-codepoint" + cs = { + codepoint = "cs1" + } + } + ] + } + }] +} +` + +func TestAccQosPolicy_DscpTos_Codepoints_Multiple(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{ + "device_group": config.ObjectVariable(map[string]config.Variable{ + "name": config.StringVariable(fmt.Sprintf("%s-dg", prefix)), + "rulebase": config.StringVariable("pre-rulebase"), + }), + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: qosPolicy_DscpTos_Codepoints_Multiple_Tmpl, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + "location": location, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_qos_policy.example", + tfjsonpath.New("rules").AtSliceIndex(0).AtMapKey("dscp_tos").AtMapKey("codepoints").AtSliceIndex(0), + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "name": knownvalue.StringExact("ef-codepoint"), + "ef": knownvalue.ObjectExact(map[string]knownvalue.Check{"codepoint": knownvalue.StringExact("ef")}), + "af": knownvalue.Null(), + "cs": knownvalue.Null(), + "tos": knownvalue.Null(), + "custom": knownvalue.Null(), + }), + ), + statecheck.ExpectKnownValue( + "panos_qos_policy.example", + tfjsonpath.New("rules").AtSliceIndex(0).AtMapKey("dscp_tos").AtMapKey("codepoints").AtSliceIndex(1), + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "name": knownvalue.StringExact("af-codepoint"), + "af": knownvalue.ObjectExact(map[string]knownvalue.Check{"codepoint": knownvalue.StringExact("af11")}), + "ef": knownvalue.Null(), + "cs": knownvalue.Null(), + "tos": knownvalue.Null(), + "custom": knownvalue.Null(), + }), + ), + statecheck.ExpectKnownValue( + "panos_qos_policy.example", + tfjsonpath.New("rules").AtSliceIndex(0).AtMapKey("dscp_tos").AtMapKey("codepoints").AtSliceIndex(2), + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "name": knownvalue.StringExact("cs-codepoint"), + "cs": knownvalue.ObjectExact(map[string]knownvalue.Check{"codepoint": knownvalue.StringExact("cs1")}), + "ef": knownvalue.Null(), + "af": knownvalue.Null(), + "tos": knownvalue.Null(), + "custom": knownvalue.Null(), + }), + ), + }, + }, + }, + }) +} + +const qosPolicy_DscpTos_Codepoints_Cs_Tmpl = ` +variable "prefix" { type = string } +variable "location" { type = any } + +resource "panos_template" "example" { + location = { panorama = {} } + name = var.prefix +} + +resource "panos_device_group" "example" { + location = { panorama = {} } + name = format("%s-dg", var.prefix) + templates = [panos_template.example.name] +} + +resource "panos_qos_policy" "example" { + depends_on = [panos_device_group.example] + location = var.location + + rules = [{ + name = format("%s-rule", var.prefix) + + source_zones = ["any"] + source_addresses = ["any"] + destination_zones = ["any"] + destination_addresses = ["any"] + applications = ["any"] + services = ["any"] + + action = { + class = "3" + } + + dscp_tos = { + codepoints = [ + { + name = "cs-codepoint" + cs = { + codepoint = "cs2" + } + } + ] + } + }] +} +` + +func TestAccQosPolicy_DscpTos_Codepoints_Cs(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{ + "device_group": config.ObjectVariable(map[string]config.Variable{ + "name": config.StringVariable(fmt.Sprintf("%s-dg", prefix)), + "rulebase": config.StringVariable("pre-rulebase"), + }), + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: qosPolicy_DscpTos_Codepoints_Cs_Tmpl, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + "location": location, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_qos_policy.example", + tfjsonpath.New("rules").AtSliceIndex(0).AtMapKey("dscp_tos").AtMapKey("codepoints").AtSliceIndex(0), + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "name": knownvalue.StringExact("cs-codepoint"), + "cs": knownvalue.ObjectExact(map[string]knownvalue.Check{"codepoint": knownvalue.StringExact("cs2")}), + "ef": knownvalue.Null(), + "af": knownvalue.Null(), + "tos": knownvalue.Null(), + "custom": knownvalue.Null(), + }), + ), + }, + }, + }, + }) +} + +const qosPolicy_DscpTos_Codepoints_Tos_Tmpl = ` +variable "prefix" { type = string } +variable "location" { type = any } + +resource "panos_template" "example" { + location = { panorama = {} } + name = var.prefix +} + +resource "panos_device_group" "example" { + location = { panorama = {} } + name = format("%s-dg", var.prefix) + templates = [panos_template.example.name] +} + +resource "panos_qos_policy" "example" { + depends_on = [panos_device_group.example] + location = var.location + + rules = [{ + name = format("%s-rule", var.prefix) + + source_zones = ["any"] + source_addresses = ["any"] + destination_zones = ["any"] + destination_addresses = ["any"] + applications = ["any"] + services = ["any"] + + action = { + class = "3" + } + + dscp_tos = { + codepoints = [ + { + name = "tos-codepoint" + tos = { + codepoint = "cs3" + } + } + ] + } + }] +} +` + +func TestAccQosPolicy_DscpTos_Codepoints_Tos(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{ + "device_group": config.ObjectVariable(map[string]config.Variable{ + "name": config.StringVariable(fmt.Sprintf("%s-dg", prefix)), + "rulebase": config.StringVariable("pre-rulebase"), + }), + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: qosPolicy_DscpTos_Codepoints_Tos_Tmpl, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + "location": location, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_qos_policy.example", + tfjsonpath.New("rules").AtSliceIndex(0).AtMapKey("dscp_tos").AtMapKey("codepoints").AtSliceIndex(0), + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "name": knownvalue.StringExact("tos-codepoint"), + "tos": knownvalue.ObjectExact(map[string]knownvalue.Check{"codepoint": knownvalue.StringExact("cs3")}), + "ef": knownvalue.Null(), + "af": knownvalue.Null(), + "cs": knownvalue.Null(), + "custom": knownvalue.Null(), + }), + ), + }, + }, + }, + }) +} + +const qosPolicy_DscpTos_Codepoints_Custom_Tmpl = ` +variable "prefix" { type = string } +variable "location" { type = any } + +resource "panos_template" "example" { + location = { panorama = {} } + name = var.prefix +} + +resource "panos_device_group" "example" { + location = { panorama = {} } + name = format("%s-dg", var.prefix) + templates = [panos_template.example.name] +} + +resource "panos_qos_policy" "example" { + depends_on = [panos_device_group.example] + location = var.location + + rules = [{ + name = format("%s-rule", var.prefix) + + source_zones = ["any"] + source_addresses = ["any"] + destination_zones = ["any"] + destination_addresses = ["any"] + applications = ["any"] + services = ["any"] + + action = { + class = "3" + } + + dscp_tos = { + codepoints = [ + { + name = "custom-codepoint" + custom = { + codepoint = { + name = "my-custom-cp" + value = "101010" + } + } + } + ] + } + }] +} +` + +func TestAccQosPolicy_DscpTos_Codepoints_Custom(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{ + "device_group": config.ObjectVariable(map[string]config.Variable{ + "name": config.StringVariable(fmt.Sprintf("%s-dg", prefix)), + "rulebase": config.StringVariable("pre-rulebase"), + }), + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: qosPolicy_DscpTos_Codepoints_Custom_Tmpl, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + "location": location, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_qos_policy.example", + tfjsonpath.New("rules").AtSliceIndex(0).AtMapKey("dscp_tos").AtMapKey("codepoints").AtSliceIndex(0), + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "name": knownvalue.StringExact("custom-codepoint"), + "custom": knownvalue.ObjectExact(map[string]knownvalue.Check{ + "codepoint": knownvalue.ObjectExact(map[string]knownvalue.Check{ + "name": knownvalue.StringExact("my-custom-cp"), + "value": knownvalue.StringExact("101010"), + }), + }), + "ef": knownvalue.Null(), + "af": knownvalue.Null(), + "cs": knownvalue.Null(), + "tos": knownvalue.Null(), + }), + ), + }, + }, + }, + }) +} + +const qosPolicy_Target_Devices_Tmpl = ` +variable "prefix" { type = string } +variable "location" { type = any } +variable "serial_number" { type = string } + +resource "panos_template" "example" { + location = { panorama = {} } + name = var.prefix +} + +resource "panos_device_group" "example" { + location = { panorama = {} } + name = format("%s-dg", var.prefix) + templates = [panos_template.example.name] +} + +resource "panos_firewall_device" "example" { + location = { panorama = {} } + name = var.serial_number +} + +resource "panos_qos_policy" "example" { + depends_on = [panos_device_group.example, panos_firewall_device.example] + location = var.location + + rules = [{ + name = format("%s-rule", var.prefix) + + source_zones = ["any"] + source_addresses = ["any"] + destination_zones = ["any"] + destination_addresses = ["any"] + applications = ["any"] + services = ["any"] + + action = { + class = "3" + } + + target = { + devices = [ + { + name = panos_firewall_device.example.name + vsys = [ + { + name = "vsys1" + } + ] + } + ] + } + }] +} +` + +func TestAccQosPolicy_Target_Devices(t *testing.T) { + t.Skip("Requires actual managed firewall devices in Panorama") + t.Parallel() + + nameSuffix := acctest.RandStringFromCharSet(6, acctest.CharSetAlphaNum) + prefix := fmt.Sprintf("test-acc-%s", nameSuffix) + suffix := acctest.RandStringFromCharSet(13, "0123456789") + serialNumber := fmt.Sprintf("00%s", suffix) + + location := config.ObjectVariable(map[string]config.Variable{ + "device_group": config.ObjectVariable(map[string]config.Variable{ + "name": config.StringVariable(fmt.Sprintf("%s-dg", prefix)), + "rulebase": config.StringVariable("pre-rulebase"), + }), + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: qosPolicy_Target_Devices_Tmpl, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + "location": location, + "serial_number": config.StringVariable(serialNumber), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_qos_policy.example", + tfjsonpath.New("rules").AtSliceIndex(0).AtMapKey("target"), + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "devices": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "name": knownvalue.StringExact(serialNumber), + "vsys": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "name": knownvalue.StringExact("vsys1"), + }), + }), + }), + }), + "negate": knownvalue.Null(), + "tags": knownvalue.Null(), + }), + ), + }, + }, + }, + }) +} + +const qosPolicy_Target_Tags_Tmpl = ` +variable "prefix" { type = string } +variable "location" { type = any } + +resource "panos_template" "example" { + location = { panorama = {} } + name = var.prefix +} + +resource "panos_device_group" "example" { + location = { panorama = {} } + name = format("%s-dg", var.prefix) + templates = [panos_template.example.name] +} + +resource "panos_qos_policy" "example" { + depends_on = [panos_device_group.example] + location = var.location + + rules = [{ + name = format("%s-rule", var.prefix) + + source_zones = ["any"] + source_addresses = ["any"] + destination_zones = ["any"] + destination_addresses = ["any"] + applications = ["any"] + services = ["any"] + + action = { + class = "3" + } + + target = { + tags = ["tag1", "tag2"] + } + }] +} +` + +func TestAccQosPolicy_Target_Tags(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{ + "device_group": config.ObjectVariable(map[string]config.Variable{ + "name": config.StringVariable(fmt.Sprintf("%s-dg", prefix)), + "rulebase": config.StringVariable("pre-rulebase"), + }), + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: qosPolicy_Target_Tags_Tmpl, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + "location": location, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_qos_policy.example", + tfjsonpath.New("rules").AtSliceIndex(0).AtMapKey("target"), + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "tags": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.StringExact("tag1"), + knownvalue.StringExact("tag2"), + }), + "devices": knownvalue.Null(), + "negate": knownvalue.Null(), + }), + ), + }, + }, + }, + }) +} + +const qosPolicy_Target_Negate_Tmpl = ` +variable "prefix" { type = string } +variable "location" { type = any } +variable "serial_number" { type = string } + +resource "panos_template" "example" { + location = { panorama = {} } + name = var.prefix +} + +resource "panos_device_group" "example" { + location = { panorama = {} } + name = format("%s-dg", var.prefix) + templates = [panos_template.example.name] +} + +resource "panos_firewall_device" "example" { + location = { panorama = {} } + name = var.serial_number +} + +resource "panos_qos_policy" "example" { + depends_on = [panos_device_group.example, panos_firewall_device.example] + location = var.location + + rules = [{ + name = format("%s-rule", var.prefix) + + source_zones = ["any"] + source_addresses = ["any"] + destination_zones = ["any"] + destination_addresses = ["any"] + applications = ["any"] + services = ["any"] + + action = { + class = "3" + } + + target = { + devices = [ + { + name = panos_firewall_device.example.name + vsys = [ + { + name = "vsys1" + } + ] + } + ] + negate = true + } + }] +} +` + +func TestAccQosPolicy_Target_Negate(t *testing.T) { + t.Skip("Requires actual managed firewall devices in Panorama") + t.Parallel() + + nameSuffix := acctest.RandStringFromCharSet(6, acctest.CharSetAlphaNum) + prefix := fmt.Sprintf("test-acc-%s", nameSuffix) + suffix := acctest.RandStringFromCharSet(13, "0123456789") + serialNumber := fmt.Sprintf("00%s", suffix) + + location := config.ObjectVariable(map[string]config.Variable{ + "device_group": config.ObjectVariable(map[string]config.Variable{ + "name": config.StringVariable(fmt.Sprintf("%s-dg", prefix)), + "rulebase": config.StringVariable("pre-rulebase"), + }), + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: qosPolicy_Target_Negate_Tmpl, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + "location": location, + "serial_number": config.StringVariable(serialNumber), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_qos_policy.example", + tfjsonpath.New("rules").AtSliceIndex(0).AtMapKey("target"), + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "devices": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "name": knownvalue.StringExact(serialNumber), + "vsys": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "name": knownvalue.StringExact("vsys1"), + }), + }), + }), + }), + "negate": knownvalue.Bool(true), + "tags": knownvalue.Null(), + }), + ), + }, + }, + }, + }) +} + +const qosPolicy_SetBehavior_Tmpl = ` +variable "prefix" { type = string } +variable "location" { type = any } + +resource "panos_template" "example" { + location = { panorama = {} } + name = var.prefix +} + +resource "panos_device_group" "example" { + location = { panorama = {} } + name = format("%s-dg", var.prefix) + templates = [panos_template.example.name] +} + +resource "panos_qos_policy" "example" { + depends_on = [panos_device_group.example] + location = var.location + + rules = [{ + name = format("%s-rule", var.prefix) + description = "Testing set behavior for destination_addresses" + + source_zones = ["any"] + source_addresses = ["any"] + source_users = ["any"] + negate_source = false + + destination_zones = ["any"] + destination_addresses = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"] + negate_destination = false + + applications = ["any"] + services = ["any"] + + action = { + class = "4" + } + + disabled = false + }] +} +` + +// panosQosPolicyReorderDestinationAddresses modifies a QoS policy rule on the server +// by reordering its destination_addresses field. Used to test set behavior. +func panosQosPolicyReorderDestinationAddresses(prefix string, ruleName string, reorderedAddresses []string) { + svc := qos.NewService(sdkClient) + + location := qos.NewDeviceGroupLocation() + location.DeviceGroup.DeviceGroup = fmt.Sprintf("%s-dg", prefix) + location.DeviceGroup.Rulebase = "pre-rulebase" + + // Construct xpath using XpathWithComponents and util.AsEntryXpath + path, err := location.XpathWithComponents(sdkClient.Versioning(), util.AsEntryXpath(ruleName)) + if err != nil { + panic(fmt.Sprintf("Failed to build xpath for QoS rule '%s': %v", ruleName, err)) + } + xpath := util.AsXpath(path) + + // Read current rule using xpath + entry, err := svc.ReadWithXpath(context.TODO(), xpath, "get") + if err != nil { + panic(fmt.Sprintf("Failed to read QoS rule '%s': %v", ruleName, err)) + } + + // Modify destination addresses + entry.Destination = reorderedAddresses + + // Update on server using xpath + err = svc.UpdateWithXpath(context.TODO(), xpath, entry, ruleName) + if err != nil { + panic(fmt.Sprintf("Failed to update QoS rule '%s': %v", ruleName, err)) + } +} + +func TestAccQosPolicy_SetBehavior(t *testing.T) { + t.Parallel() + + nameSuffix := acctest.RandStringFromCharSet(6, acctest.CharSetAlphaNum) + prefix := fmt.Sprintf("test-acc-%s", nameSuffix) + ruleName := fmt.Sprintf("%s-rule", prefix) + + location := config.ObjectVariable(map[string]config.Variable{ + "device_group": config.ObjectVariable(map[string]config.Variable{ + "name": config.StringVariable(fmt.Sprintf("%s-dg", prefix)), + "rulebase": config.StringVariable("pre-rulebase"), + }), + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + // Step 1: Create with ordered addresses + { + Config: qosPolicy_SetBehavior_Tmpl, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + "location": location, + }, + ConfigStateChecks: []statecheck.StateCheck{ + // Verify addresses using SetExact (order-independent) + statecheck.ExpectKnownValue( + "panos_qos_policy.example", + tfjsonpath.New("rules").AtSliceIndex(0).AtMapKey("destination_addresses"), + knownvalue.SetExact([]knownvalue.Check{ + knownvalue.StringExact("10.0.1.0/24"), + knownvalue.StringExact("10.0.2.0/24"), + knownvalue.StringExact("10.0.3.0/24"), + }), + ), + }, + }, + // Step 2: Reorder via SDK, verify no drift + { + Config: qosPolicy_SetBehavior_Tmpl, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + "location": location, + }, + PreConfig: func() { + panosQosPolicyReorderDestinationAddresses( + prefix, + ruleName, + []string{"10.0.3.0/24", "10.0.1.0/24", "10.0.2.0/24"}, + ) + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + }, + }, + }) +} + +func TestAccQosPolicy_SetBehavior_DetectsChanges(t *testing.T) { + t.Parallel() + + nameSuffix := acctest.RandStringFromCharSet(6, acctest.CharSetAlphaNum) + prefix := fmt.Sprintf("test-acc-%s", nameSuffix) + ruleName := fmt.Sprintf("%s-rule", prefix) + + location := config.ObjectVariable(map[string]config.Variable{ + "device_group": config.ObjectVariable(map[string]config.Variable{ + "name": config.StringVariable(fmt.Sprintf("%s-dg", prefix)), + "rulebase": config.StringVariable("pre-rulebase"), + }), + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + // Step 1: Create with 3 addresses + { + Config: qosPolicy_SetBehavior_Tmpl, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + "location": location, + }, + }, + // Step 2: Change content (not just order), verify drift detected + { + Config: qosPolicy_SetBehavior_Tmpl, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + "location": location, + }, + PreConfig: func() { + // Replace one address with different IP + panosQosPolicyReorderDestinationAddresses( + prefix, + ruleName, + []string{"10.0.4.0/24", "10.0.1.0/24", "10.0.2.0/24"}, // Changed first address + ) + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectNonEmptyPlan(), // Plan SHOULD show changes + }, + }, + }, + }, + }) +} diff --git a/pkg/translate/terraform_provider/terraform_provider_file.go b/pkg/translate/terraform_provider/terraform_provider_file.go index 90ab354e..62c07ef8 100644 --- a/pkg/translate/terraform_provider/terraform_provider_file.go +++ b/pkg/translate/terraform_provider/terraform_provider_file.go @@ -122,6 +122,17 @@ func (g *GenerateTerraformProvider) generateTerraformEntityTemplate(resourceTyp return g.executeTemplate(template, spec, terraformProvider, resourceTyp, schemaTyp, names) } +func locationVariablesWithDefaults(locations map[string]*properties.Location) bool { + for _, location := range locations { + for _, variable := range location.Vars { + if variable.Default != "" { + return true + } + } + } + return false +} + // GenerateTerraformResource generates a Terraform resource template. func (g *GenerateTerraformProvider) GenerateTerraformResource(resourceTyp properties.ResourceType, spec *properties.Normalization, terraformProvider *properties.TerraformProviderFile) error { names := NewNameProvider(spec, resourceTyp) @@ -314,7 +325,9 @@ func (g *GenerateTerraformProvider) GenerateTerraformResource(resourceTyp proper if len(spec.Locations) > 0 { terraformProvider.ImportManager.AddHashicorpImport("github.com/hashicorp/terraform-plugin-framework/diag", "") - terraformProvider.ImportManager.AddHashicorpImport("github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault", "") + if locationVariablesWithDefaults(spec.Locations) { + terraformProvider.ImportManager.AddHashicorpImport("github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault", "") + } if resourceTyp != properties.ResourceCustom { terraformProvider.ImportManager.AddHashicorpImport("github.com/hashicorp/terraform-plugin-log/tflog", "") } @@ -458,7 +471,9 @@ func (g *GenerateTerraformProvider) GenerateTerraformDataSource(resourceTyp prop terraformProvider.ImportManager.AddHashicorpImport("github.com/hashicorp/terraform-plugin-framework/attr", "") terraformProvider.ImportManager.AddHashicorpImport("github.com/hashicorp/terraform-plugin-framework/diag", "") terraformProvider.ImportManager.AddHashicorpImport("github.com/hashicorp/terraform-plugin-framework/resource/schema", "rsschema") - terraformProvider.ImportManager.AddHashicorpImport("github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault", "") + if locationVariablesWithDefaults(spec.Locations) { + terraformProvider.ImportManager.AddHashicorpImport("github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault", "") + } names := NewNameProvider(spec, resourceTyp) funcMap := template.FuncMap{ diff --git a/specs/panorama/devices.yaml b/specs/panorama/devices.yaml new file mode 100644 index 00000000..1146674f --- /dev/null +++ b/specs/panorama/devices.yaml @@ -0,0 +1,115 @@ +name: mgt-config-devices +terraform_provider_config: + description: Firewall Devices + skip_resource: false + skip_datasource: false + resource_type: entry + resource_variants: + - singular + suffix: firewall_device + plural_description: "" +go_sdk_config: + skip: false + package: + - panorama + - devices +panos_xpath: + path: + - mgt-config + - devices + vars: [] +locations: + - name: panorama + xpath: + path: + - config + vars: [] + description: Located in a panorama. + validators: [] + required: false + read_only: false +entries: + - name: name + description: "" + validators: [] +spec: + params: + - name: auto-push + type: bool + profiles: + - xpath: + - auto-push + validators: [] + spec: {} + description: "" + required: false + - name: disable-config-backup + type: bool + profiles: + - xpath: + - disable-config-backup + validators: [] + spec: {} + description: Enable config back up for this device + required: false + - name: hostname + type: string + profiles: + - xpath: + - hostname + validators: [] + spec: {} + description: ip address + required: false + - name: ip + type: string + profiles: + - xpath: + - ip + validators: [] + spec: {} + description: ip address + required: false + - name: to-sw-version + type: string + profiles: + - xpath: + - to-sw-version + validators: + - type: length + spec: + max: 64 + spec: {} + description: Automatically upgrade software to this version for new deployments + required: false + - name: vsys + type: list + profiles: + - xpath: + - vsys + - entry + type: entry + validators: [] + spec: + type: object + items: + type: object + spec: + params: + - name: tags + type: list + profiles: + - xpath: + - tags + type: member + validators: [] + spec: + type: string + items: + type: string + description: "" + required: false + variants: [] + description: "" + required: false + variants: [] diff --git a/specs/policies/qos-policy.yaml b/specs/policies/qos-policy.yaml new file mode 100644 index 00000000..296b8c0b --- /dev/null +++ b/specs/policies/qos-policy.yaml @@ -0,0 +1,736 @@ +name: QoS Policy +terraform_provider_config: + description: QoS policy rule + skip_resource: false + skip_datasource: false + resource_type: uuid + resource_variants: + - singular + - plural + suffix: qos_policy + plural_suffix: qos_policy_rules + plural_name: rules + plural_description: '' +go_sdk_config: + skip: false + package: + - policies + - rules + - qos +panos_xpath: + path: + - qos + - rules + vars: [] +locations: +- name: shared + xpath: + path: + - config + - shared + - $rulebase + vars: + - name: rulebase + description: Rulebase name + required: false + default: pre-rulebase + validators: + - type: values + spec: + values: + - pre-rulebase + - post-rulebase + type: object + description: Located in a shared rulebase + devices: + - panorama + - ngfw + validators: [] + required: false + read_only: false +- name: vsys + xpath: + path: + - config + - devices + - $ngfw_device + - vsys + - $vsys + - rulebase + vars: + - name: ngfw_device + description: The NGFW device + required: false + default: localhost.localdomain + validators: [] + type: entry + - name: vsys + description: The vsys name + required: false + default: vsys1 + validators: + - type: not-values + spec: + values: + - value: shared + error: The vsys cannot be "shared". Use the "shared" location instead. + type: entry + description: Located in a specific vsys rulebase + devices: + - ngfw + validators: [] + required: false + read_only: false +- name: device-group + xpath: + path: + - config + - devices + - $panorama_device + - device-group + - $device_group + - $rulebase + vars: + - name: panorama_device + description: The panorama device + required: false + default: localhost.localdomain + validators: [] + type: entry + - name: device_group + description: The device group name + required: true + validators: + - type: not-values + spec: + values: + - value: shared + error: The device group cannot be "shared". Use the "shared" location + instead. + type: entry + location_filter: true + - name: rulebase + description: The rulebase + required: false + default: pre-rulebase + validators: + - type: values + spec: + values: + - pre-rulebase + - post-rulebase + type: object + description: Located in a specific device group rulebase + devices: + - panorama + validators: [] + required: false + read_only: false +entries: +- name: name + description: '' + validators: [] +spec: + params: + - name: action + type: object + profiles: + - xpath: + - action + validators: [] + spec: + params: + - name: class + type: enum + profiles: + - xpath: + - class + validators: + - type: values + spec: + values: + - '1' + - '2' + - '3' + - '4' + - '5' + - '6' + - '7' + - '8' + spec: + values: + - value: '1' + - value: '2' + - value: '3' + - value: '4' + - value: '5' + - value: '6' + - value: '7' + - value: '8' + description: assigned class + required: false + variants: [] + description: classification action + required: false + - name: application + type: list + profiles: + - xpath: + - application + type: member + validators: [] + spec: + type: string + items: + type: string + description: '' + required: false + codegen_overrides: + terraform: + type: set + name: applications + - name: category + type: list + profiles: + - xpath: + - category + type: member + validators: [] + spec: + type: string + items: + type: string + description: '' + required: false + - name: description + type: string + profiles: + - xpath: + - description + validators: + - type: length + spec: + min: 0 + max: 1024 + spec: {} + description: '' + required: false + - name: destination + type: list + profiles: + - xpath: + - destination + type: member + validators: [] + spec: + type: string + items: + type: string + description: '' + required: false + codegen_overrides: + terraform: + type: set + name: destination-addresses + - name: destination-hip + type: list + profiles: + - xpath: + - destination-hip + type: member + validators: [] + spec: + type: string + items: + type: string + description: '' + required: false + - name: disabled + type: bool + profiles: + - xpath: + - disabled + validators: [] + spec: {} + description: Disable the rule + required: false + - name: dscp-tos + type: object + profiles: + - xpath: + - dscp-tos + validators: [] + spec: + params: [] + variants: + - name: any + type: object + profiles: + - xpath: + - any + validators: [] + spec: + params: [] + variants: [] + description: any codepoint + required: false + - name: codepoints + type: list + profiles: + - xpath: + - codepoints + - entry + type: entry + validators: [] + spec: + type: object + items: + type: object + spec: + params: [] + variants: + - name: ef + type: object + profiles: + - xpath: + - ef + validators: [] + spec: + params: + - name: codepoint + type: enum + profiles: + - xpath: + - codepoint + validators: + - type: values + spec: + values: + - ef + spec: + values: + - value: ef + description: '' + required: false + variants: [] + description: Expedited Forwarding (EF) + required: false + variant_group_id: 0 + - name: af + type: object + profiles: + - xpath: + - af + validators: [] + spec: + params: + - name: codepoint + type: enum + profiles: + - xpath: + - codepoint + validators: + - type: values + spec: + values: + - af11 + - af12 + - af13 + - af21 + - af22 + - af23 + - af31 + - af32 + - af33 + - af41 + - af42 + - af43 + spec: + values: + - value: af11 + - value: af12 + - value: af13 + - value: af21 + - value: af22 + - value: af23 + - value: af31 + - value: af32 + - value: af33 + - value: af41 + - value: af42 + - value: af43 + description: '' + required: false + variants: [] + description: Assured Forwarding (AF) + required: false + variant_group_id: 0 + - name: cs + type: object + profiles: + - xpath: + - cs + validators: [] + spec: + params: + - name: codepoint + type: enum + profiles: + - xpath: + - codepoint + validators: + - type: values + spec: + values: + - cs0 + - cs1 + - cs2 + - cs3 + - cs4 + - cs5 + - cs6 + - cs7 + spec: + values: + - value: cs0 + - value: cs1 + - value: cs2 + - value: cs3 + - value: cs4 + - value: cs5 + - value: cs6 + - value: cs7 + description: '' + required: false + variants: [] + description: Class Selector (CS) + required: false + variant_group_id: 0 + - name: tos + type: object + profiles: + - xpath: + - tos + validators: [] + spec: + params: + - name: codepoint + type: enum + profiles: + - xpath: + - codepoint + validators: + - type: values + spec: + values: + - cs0 + - cs1 + - cs2 + - cs3 + - cs4 + - cs5 + - cs6 + - cs7 + spec: + values: + - value: cs0 + - value: cs1 + - value: cs2 + - value: cs3 + - value: cs4 + - value: cs5 + - value: cs6 + - value: cs7 + description: '' + required: false + variants: [] + description: IP Precedence (ToS) + required: false + variant_group_id: 0 + - name: custom + type: object + profiles: + - xpath: + - custom + validators: [] + spec: + params: + - name: codepoint + type: object + profiles: + - xpath: + - codepoint + validators: [] + spec: + params: + - name: name + type: string + profiles: + - xpath: + - name + validators: + - type: length + spec: + max: 31 + spec: {} + description: alphanumeric string [ 0-9a-zA-Z._-] + required: false + - name: value + type: string + profiles: + - xpath: + - value + validators: [] + spec: {} + description: codepoint in format 'xxxxxx' where x is {0|1} + required: false + variants: [] + description: '' + required: false + variants: [] + description: Custom Code Point + required: false + variant_group_id: 0 + description: '' + required: false + codegen_overrides: + terraform: + variant_check: Disabled + description: '' + required: false + - name: from + type: list + profiles: + - xpath: + - from + type: member + validators: [] + spec: + type: string + items: + type: string + description: '' + required: false + codegen_overrides: + terraform: + type: set + name: source-zones + - name: group-tag + type: string + profiles: + - xpath: + - group-tag + validators: + - type: length + spec: + max: 127 + spec: {} + description: '' + required: false + - name: negate-destination + type: bool + profiles: + - xpath: + - negate-destination + validators: [] + spec: {} + description: '' + required: false + - name: negate-source + type: bool + profiles: + - xpath: + - negate-source + validators: [] + spec: {} + description: '' + required: false + - name: schedule + type: string + profiles: + - xpath: + - schedule + validators: [] + spec: {} + description: '' + required: false + - name: service + type: list + profiles: + - xpath: + - service + type: member + validators: [] + spec: + type: string + items: + type: string + description: '' + required: false + codegen_overrides: + terraform: + type: set + name: services + - name: source + type: list + profiles: + - xpath: + - source + type: member + validators: [] + spec: + type: string + items: + type: string + description: '' + required: false + codegen_overrides: + terraform: + type: set + name: source-addresses + - name: source-hip + type: list + profiles: + - xpath: + - source-hip + type: member + validators: [] + spec: + type: string + items: + type: string + description: '' + required: false + - name: source-user + type: list + profiles: + - xpath: + - source-user + type: member + validators: [] + spec: + type: string + items: + type: string + description: '' + required: false + codegen_overrides: + terraform: + type: set + name: source-users + - name: tag + type: list + profiles: + - xpath: + - tag + type: member + validators: [] + spec: + type: string + items: + type: string + description: '' + required: false + - name: target + type: object + profiles: + - xpath: + - target + validators: [] + spec: + params: + - name: devices + type: list + profiles: + - xpath: + - devices + - entry + type: entry + validators: [] + spec: + type: object + items: + type: object + spec: + params: + - name: vsys + type: list + profiles: + - xpath: + - vsys + - entry + type: entry + validators: [] + spec: + type: object + items: + type: object + spec: + params: [] + variants: [] + description: '' + required: false + variants: [] + description: '' + required: false + - name: negate + type: bool + profiles: + - xpath: + - negate + validators: [] + spec: {} + description: Target to all but these specified devices and tags + required: false + - name: tags + type: list + profiles: + - xpath: + - tags + type: member + validators: [] + spec: + type: string + items: + type: string + description: '' + required: false + variants: [] + description: Target devices + required: false + - name: to + type: list + profiles: + - xpath: + - to + type: member + validators: [] + spec: + type: string + items: + type: string + description: '' + required: false + codegen_overrides: + terraform: + type: set + name: destination-zones + - name: uuid + type: string + profiles: + - xpath: + - uuid + validators: + - type: regexp + spec: + expr: '[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}' + - type: length + spec: + min: 36 + max: 36 + description: Entry UUID value + required: false + codegen_overrides: + terraform: + private: true + variants: []