From 5dd28ceccc07a30d00c759a7dbe8fa87ac083924 Mon Sep 17 00:00:00 2001 From: Krzysztof Klimonda Date: Fri, 13 Dec 2024 10:17:03 +0100 Subject: [PATCH 1/2] feat(specs): Initial panos_log_forwarding codegen spec --- specs/objects/profiles/log-forwarding.yaml | 444 +++++++++++++++++++++ 1 file changed, 444 insertions(+) create mode 100644 specs/objects/profiles/log-forwarding.yaml diff --git a/specs/objects/profiles/log-forwarding.yaml b/specs/objects/profiles/log-forwarding.yaml new file mode 100644 index 00000000..112d62ba --- /dev/null +++ b/specs/objects/profiles/log-forwarding.yaml @@ -0,0 +1,444 @@ +name: log-forwarding-profile +terraform_provider_config: + description: Log Forwarding Profile + skip_resource: false + skip_datasource: false + resource_type: entry + resource_variants: [] + suffix: log_forwarding_profile + plural_suffix: '' + plural_name: '' + plural_description: '' +go_sdk_config: + skip: false + package: + - objects + - profiles + - logforwarding +xpath_suffix: +- log-settings +- profiles +locations: +- name: shared + xpath: + path: + - config + - shared + vars: [] + description: Location in Shared Panorama + devices: + - panorama + - ngfw + validators: [] + required: false + read_only: false +- name: device-group + xpath: + path: + - config + - devices + - $panorama_device + - device-group + - $device_group + vars: + - name: panorama_device + description: Panorama device name + required: false + default: localhost.localdomain + validators: [] + type: entry + - name: device_group + description: Device Group name + required: true + validators: + - type: not-values + spec: + values: + - value: shared + error: The device group name cannot be "shared". Use the "shared" location + instead + type: entry + description: Located in a specific Device Group + devices: + - panorama + validators: [] + required: false + read_only: false +entries: +- name: name + description: '' + validators: [] +imports: [] +spec: + params: + - name: description + type: string + profiles: + - xpath: + - description + validators: + - type: length + spec: + max: 1023 + spec: {} + description: '' + required: false + - name: disable-override + type: enum + profiles: + - xpath: + - disable-override + validators: + - type: values + spec: + values: + - 'yes' + - 'no' + spec: + default: 'no' + values: + - value: 'yes' + - value: 'no' + description: disable object override in child device groups + required: false + - name: enhanced-application-logging + type: bool + profiles: + - xpath: + - enhanced-application-logging + validators: [] + spec: {} + description: Enabling enhanced-application-logging + required: false + - name: match-list + type: list + profiles: + - xpath: + - match-list + - entry + type: entry + validators: [] + spec: + type: object + items: + type: object + spec: + params: + - name: action-desc + type: string + profiles: + - xpath: + - action-desc + validators: + - type: length + spec: + max: 1023 + spec: {} + description: '' + required: false + - name: log-type + type: enum + profiles: + - xpath: + - log-type + validators: + - type: values + spec: + values: + - traffic + - threat + - wildfire + - url + - data + - gtp + - sctp + - tunnel + - auth + - decryption + spec: + default: traffic + values: + - value: traffic + - value: threat + - value: wildfire + - value: url + - value: data + - value: gtp + - value: sctp + - value: tunnel + - value: auth + - value: decryption + description: Pick log type + required: false + - name: filter + type: string + profiles: + - xpath: + - filter + validators: + - type: length + spec: + max: 1023 + spec: {} + description: '' + required: false + - name: send-to-panorama + type: bool + profiles: + - xpath: + - send-to-panorama + validators: [] + spec: {} + description: '' + required: false + - name: quarantine + type: bool + profiles: + - xpath: + - quarantine + validators: [] + spec: {} + description: '' + required: false + - name: send-snmptrap + type: list + profiles: + - xpath: + - send-snmptrap + type: member + validators: [] + spec: + type: string + items: + type: string + description: '' + required: false + - name: send-email + type: list + profiles: + - xpath: + - send-email + type: member + validators: [] + spec: + type: string + items: + type: string + description: '' + required: false + - name: send-syslog + type: list + profiles: + - xpath: + - send-syslog + type: member + validators: [] + spec: + type: string + items: + type: string + description: '' + required: false + - name: send-http + type: list + profiles: + - xpath: + - send-http + type: member + validators: [] + spec: + type: string + items: + type: string + description: '' + required: false + - name: actions + type: list + profiles: + - xpath: + - actions + - entry + type: entry + validators: [] + spec: + type: object + items: + type: object + spec: + params: + - name: type + type: object + profiles: + - xpath: + - type + validators: [] + spec: + params: [] + variants: + - name: integration + type: object + profiles: + - xpath: + - integration + validators: [] + spec: + params: + - name: action + type: enum + profiles: + - xpath: + - action + validators: + - type: values + spec: + values: + - Azure-Security-Center-Integration + spec: + default: Azure-Security-Center-Integration + values: + - value: Azure-Security-Center-Integration + description: '' + required: false + variants: [] + description: '' + required: false + - name: tagging + type: object + profiles: + - xpath: + - tagging + validators: [] + spec: + params: + - name: target + type: enum + profiles: + - xpath: + - target + validators: + - type: values + spec: + values: + - source-address + - destination-address + - xff-address + - user + spec: + default: source-address + values: + - value: source-address + - value: destination-address + - value: xff-address + - value: user + description: '' + required: false + - name: action + type: enum + profiles: + - xpath: + - action + validators: + - type: values + spec: + values: + - add-tag + - remove-tag + spec: + default: add-tag + values: + - value: add-tag + - value: remove-tag + description: '' + required: false + - name: timeout + type: int64 + profiles: + - xpath: + - timeout + validators: + - type: length + spec: + min: 0 + max: 43200 + spec: + default: 0 + description: timeout in minutes + required: false + - name: registration + type: object + profiles: + - xpath: + - registration + validators: [] + spec: + params: [] + variants: + - name: localhost + type: object + profiles: + - xpath: + - localhost + validators: [] + spec: + params: [] + variants: [] + description: Local User-ID + required: false + - name: panorama + type: object + profiles: + - xpath: + - panorama + validators: [] + spec: + params: [] + variants: [] + description: Panorama User-ID + required: false + - name: remote + type: object + profiles: + - xpath: + - remote + validators: [] + spec: + params: + - name: http-profile + type: string + profiles: + - xpath: + - http-profile + validators: [] + spec: {} + description: '' + required: false + variants: [] + description: Remote User-ID + required: false + description: '' + required: false + - name: tags + type: list + profiles: + - xpath: + - tags + type: member + validators: [] + spec: + type: string + items: + type: string + description: '' + required: false + variants: [] + description: '' + required: false + description: '' + required: false + variants: [] + description: '' + required: false + variants: [] + description: '' + required: false + variants: [] From 0ca46b278bb7478f21caa0bc7142811ea32798a3 Mon Sep 17 00:00:00 2001 From: Krzysztof Klimonda Date: Mon, 16 Dec 2024 14:24:30 +0100 Subject: [PATCH 2/2] feat(tests): Initial panos_log_forwarding_profile terraform acceptance tests --- .../test/resource_log_forwarding_test.go | 374 ++++++++++++++++++ 1 file changed, 374 insertions(+) create mode 100644 assets/terraform/test/resource_log_forwarding_test.go diff --git a/assets/terraform/test/resource_log_forwarding_test.go b/assets/terraform/test/resource_log_forwarding_test.go new file mode 100644 index 00000000..c95b22ae --- /dev/null +++ b/assets/terraform/test/resource_log_forwarding_test.go @@ -0,0 +1,374 @@ +package provider_test + +import ( + "context" + "errors" + "fmt" + "strings" + "testing" + + sdkErrors "github.com/PaloAltoNetworks/pango/errors" + "github.com/PaloAltoNetworks/pango/objects/profiles/logforwarding" + + "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/terraform" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" +) + +func TestAccLogForwarding(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, + CheckDestroy: testAccLogForwardingDestroy(prefix), + Steps: []resource.TestStep{ + { + Config: logForwardingResource1, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_log_forwarding_profile.profile", + tfjsonpath.New("name"), + knownvalue.StringExact(fmt.Sprintf("%s-profile", prefix)), + ), + statecheck.ExpectKnownValue( + "panos_log_forwarding_profile.profile", + tfjsonpath.New("disable_override"), + knownvalue.StringExact("no"), + ), + statecheck.ExpectKnownValue( + "panos_log_forwarding_profile.profile", + tfjsonpath.New("enhanced_application_logging"), + knownvalue.Bool(true), + ), + statecheck.ExpectKnownValue( + "panos_log_forwarding_profile.profile", + tfjsonpath.New("match_list"). + AtSliceIndex(0). + AtMapKey("name"), + knownvalue.StringExact(fmt.Sprintf("%s-match1", prefix)), + ), + statecheck.ExpectKnownValue( + "panos_log_forwarding_profile.profile", + tfjsonpath.New("match_list"). + AtSliceIndex(0). + AtMapKey("action_desc"), + knownvalue.StringExact("action description"), + ), + // match_list[0].actions[0] + statecheck.ExpectKnownValue( + "panos_log_forwarding_profile.profile", + tfjsonpath.New("match_list"). + AtSliceIndex(0). + AtMapKey("actions"). + AtSliceIndex(0). + AtMapKey("name"), + knownvalue.StringExact(fmt.Sprintf("%s-action1", prefix)), + ), + statecheck.ExpectKnownValue( + "panos_log_forwarding_profile.profile", + tfjsonpath.New("match_list"). + AtSliceIndex(0). + AtMapKey("actions"). + AtSliceIndex(0). + AtMapKey("type"). + AtMapKey("integration"). + AtMapKey("action"), + knownvalue.StringExact("Azure-Security-Center-Integration"), + ), + // match_list[0].actions[1] + statecheck.ExpectKnownValue( + "panos_log_forwarding_profile.profile", + tfjsonpath.New("match_list"). + AtSliceIndex(0). + AtMapKey("actions"). + AtSliceIndex(1). + AtMapKey("name"), + knownvalue.StringExact(fmt.Sprintf("%s-action2", prefix)), + ), + statecheck.ExpectKnownValue( + "panos_log_forwarding_profile.profile", + tfjsonpath.New("match_list"). + AtSliceIndex(0). + AtMapKey("actions"). + AtSliceIndex(1). + AtMapKey("type"). + AtMapKey("tagging"). + AtMapKey("action"), + knownvalue.StringExact("add-tag"), + ), + statecheck.ExpectKnownValue( + "panos_log_forwarding_profile.profile", + tfjsonpath.New("match_list"). + AtSliceIndex(0). + AtMapKey("actions"). + AtSliceIndex(1). + AtMapKey("type"). + AtMapKey("tagging"). + AtMapKey("registration"). + AtMapKey("localhost"), + knownvalue.ObjectExact(map[string]knownvalue.Check{}), + ), + statecheck.ExpectKnownValue( + "panos_log_forwarding_profile.profile", + tfjsonpath.New("match_list"). + AtSliceIndex(0). + AtMapKey("actions"). + AtSliceIndex(1). + AtMapKey("type"). + AtMapKey("tagging"). + AtMapKey("tags"), + knownvalue.ListSizeExact(0), + ), + statecheck.ExpectKnownValue( + "panos_log_forwarding_profile.profile", + tfjsonpath.New("match_list"). + AtSliceIndex(0). + AtMapKey("actions"). + AtSliceIndex(1). + AtMapKey("type"). + AtMapKey("tagging"). + AtMapKey("target"), + knownvalue.StringExact("source-address"), + ), + statecheck.ExpectKnownValue( + "panos_log_forwarding_profile.profile", + tfjsonpath.New("match_list"). + AtSliceIndex(0). + AtMapKey("actions"). + AtSliceIndex(1). + AtMapKey("type"). + AtMapKey("tagging"). + AtMapKey("timeout"), + knownvalue.Int64Exact(3600), + ), + // match_list[0].actions[2] + statecheck.ExpectKnownValue( + "panos_log_forwarding_profile.profile", + tfjsonpath.New("match_list"). + AtSliceIndex(0). + AtMapKey("actions"). + AtSliceIndex(2). + AtMapKey("name"), + knownvalue.StringExact(fmt.Sprintf("%s-action3", prefix)), + ), + statecheck.ExpectKnownValue( + "panos_log_forwarding_profile.profile", + tfjsonpath.New("match_list"). + AtSliceIndex(0). + AtMapKey("actions"). + AtSliceIndex(2). + AtMapKey("type"). + AtMapKey("tagging"). + AtMapKey("action"), + knownvalue.StringExact("remove-tag"), + ), + statecheck.ExpectKnownValue( + "panos_log_forwarding_profile.profile", + tfjsonpath.New("match_list"). + AtSliceIndex(0). + AtMapKey("actions"). + AtSliceIndex(2). + AtMapKey("type"). + AtMapKey("tagging"). + AtMapKey("registration"). + AtMapKey("panorama"), + knownvalue.ObjectExact(map[string]knownvalue.Check{}), + ), + statecheck.ExpectKnownValue( + "panos_log_forwarding_profile.profile", + tfjsonpath.New("match_list"). + AtSliceIndex(0). + AtMapKey("actions"). + AtSliceIndex(2). + AtMapKey("type"). + AtMapKey("tagging"). + AtMapKey("target"), + knownvalue.StringExact("user"), + ), + statecheck.ExpectKnownValue( + "panos_log_forwarding_profile.profile", + tfjsonpath.New("match_list"). + AtSliceIndex(0). + AtMapKey("actions"). + AtSliceIndex(2). + AtMapKey("type"). + AtMapKey("tagging"). + AtMapKey("tags"), + knownvalue.ListExact([]knownvalue.Check{ + knownvalue.StringExact(fmt.Sprintf("%s-tag1", prefix)), + knownvalue.StringExact(fmt.Sprintf("%s-tag2", prefix)), + }), + ), + // match_list[0].actions[3] + statecheck.ExpectKnownValue( + "panos_log_forwarding_profile.profile", + tfjsonpath.New("match_list"). + AtSliceIndex(0). + AtMapKey("actions"). + AtSliceIndex(3). + AtMapKey("name"), + knownvalue.StringExact(fmt.Sprintf("%s-action4", prefix)), + ), + statecheck.ExpectKnownValue( + "panos_log_forwarding_profile.profile", + tfjsonpath.New("match_list"). + AtSliceIndex(0). + AtMapKey("actions"). + AtSliceIndex(3). + AtMapKey("type"). + AtMapKey("tagging"). + AtMapKey("action"), + knownvalue.StringExact("add-tag"), + ), + statecheck.ExpectKnownValue( + "panos_log_forwarding_profile.profile", + tfjsonpath.New("match_list"). + AtSliceIndex(0). + AtMapKey("actions"). + AtSliceIndex(3). + AtMapKey("type"). + AtMapKey("tagging"). + AtMapKey("target"), + knownvalue.StringExact("source-address"), + ), + statecheck.ExpectKnownValue( + "panos_log_forwarding_profile.profile", + tfjsonpath.New("match_list"). + AtSliceIndex(0). + AtMapKey("actions"). + AtSliceIndex(3). + AtMapKey("type"). + AtMapKey("tagging"). + AtMapKey("registration"). + AtMapKey("remote"). + AtMapKey("http_profile"), + knownvalue.StringExact("http-profile"), + ), + }, + }, + }, + }) +} + +const logForwardingResource1 = ` +variable "prefix" { type = string } + +locals { + device_group = format("%s-dg", var.prefix) +} + +resource "panos_device_group" "dg" { + location = { panorama = {} } + + name = local.device_group +} + +resource "panos_log_forwarding_profile" "profile" { + location = { device_group = { name = panos_device_group.dg.name } } + + name = format("%s-profile", var.prefix) + + disable_override = "no" + + enhanced_application_logging = true + + match_list = [{ + name = format("%s-match1", var.prefix) + + action_desc = "action description" + actions = [ + { + name = format("%s-action1", var.prefix) + type = { integration = { action = "Azure-Security-Center-Integration" } } + }, + { + name = format("%s-action2", var.prefix) + type = { + tagging = { + action = "add-tag" + registration = { localhost = {} } + tags = [] + target = "source-address" + timeout = 3600 + } + } + }, + { + name = format("%s-action3", var.prefix) + type = { + tagging = { + action = "remove-tag" + registration = { panorama = {} } + target = "user" + tags = [format("%s-tag1", var.prefix), format("%s-tag2", var.prefix)] + } + } + }, + { + name = format("%s-action4", var.prefix) + type = { + tagging = { + action = "add-tag" + target = "source-address" + registration = { remote = { http_profile = "http-profile" } } + } + } + }, + ] + filter = "All Logs" + log_type = "traffic" + quarantine = true + send_email = ["test@example.com"] + send_http = ["http://example.com"] + send_snmptrap = ["trap.example.com"] + send_syslog = ["syslog.example.com"] + send_to_panorama = true + }] +} +` + +func testAccLogForwardingDestroy(prefix string) func(s *terraform.State) error { + return func(s *terraform.State) error { + api := logforwarding.NewService(sdkClient) + ctx := context.TODO() + + location := logforwarding.NewDeviceGroupLocation() + location.DeviceGroup = &logforwarding.DeviceGroupLocation{ + DeviceGroup: fmt.Sprintf("%s-dg", prefix), + PanoramaDevice: "localhost.localdomain", + } + + entries, err := api.List(ctx, *location, "get", "", "") + if err != nil && !sdkErrors.IsObjectNotFound(err) { + return fmt.Errorf("error while listing entries via sdk: %v", err) + } + + var leftEntries []string + for _, elt := range entries { + if strings.HasPrefix(elt.Name, prefix) { + leftEntries = append(leftEntries, elt.Name) + } + } + + if len(leftEntries) > 0 { + err := fmt.Errorf("terraform failed to remove entries from the server") + delErr := api.Delete(ctx, *location, leftEntries...) + if delErr != nil { + return errors.Join(err, delErr) + } + return err + } + + return nil + } +}