diff --git a/assets/terraform/examples/resources/panos_schedule/import.sh b/assets/terraform/examples/resources/panos_schedule/import.sh new file mode 100644 index 00000000..c59c7474 --- /dev/null +++ b/assets/terraform/examples/resources/panos_schedule/import.sh @@ -0,0 +1,12 @@ +# A schedule can be imported by providing the following base64 encoded object as the ID +# { +# location = { +# device_group = { +# name = "example-device-group" +# panorama_device = "localhost.localdomain" +# } +# } +# +# name = "daily-schedule" +# } +terraform import panos_schedule.example $(echo '{"location":{"device_group":{"name":"example-device-group","panorama_device":"localhost.localdomain"}},"name":"daily-schedule"}' | base64) diff --git a/assets/terraform/examples/resources/panos_schedule/resource.tf b/assets/terraform/examples/resources/panos_schedule/resource.tf new file mode 100644 index 00000000..377ba4a7 --- /dev/null +++ b/assets/terraform/examples/resources/panos_schedule/resource.tf @@ -0,0 +1,64 @@ +resource "panos_schedule" "non_recurring" { + location = { + device_group = { + name = panos_device_group.example.name + } + } + + name = "non-recurring-schedule" + disable_override = "yes" + schedule_type = { + non_recurring = [ + "2025/01/01@00:00-2025/01/31@23:59", + "2025/12/24@00:00-2025/12/26@23:59" + ] + } +} + +resource "panos_schedule" "daily" { + location = { + device_group = { + name = panos_device_group.example.name + } + } + + name = "daily-schedule" + disable_override = "yes" + schedule_type = { + recurring = { + daily = ["09:00-17:00", "18:00-22:00"] + } + } +} + +resource "panos_schedule" "weekly" { + location = { + device_group = { + name = panos_device_group.example.name + } + } + + name = "weekly-schedule" + disable_override = "yes" + schedule_type = { + recurring = { + weekly = { + monday = ["08:00-12:00", "13:00-17:00"] + tuesday = ["08:00-12:00", "13:00-17:00"] + wednesday = ["08:00-12:00", "13:00-17:00"] + thursday = ["08:00-12:00", "13:00-17:00"] + friday = ["08:00-12:00", "13:00-17:00"] + saturday = ["10:00-14:00"] + sunday = ["10:00-14:00"] + } + } + } +} + +resource "panos_device_group" "example" { + location = { + panorama = {} + } + + name = "example-device-group" +} diff --git a/assets/terraform/test/resource_schedule_test.go b/assets/terraform/test/resource_schedule_test.go new file mode 100644 index 00000000..a63e98c2 --- /dev/null +++ b/assets/terraform/test/resource_schedule_test.go @@ -0,0 +1,365 @@ +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 TestAccSchedule_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(prefix), + }), + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: schedule_Basic_Tmpl, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + "location": location, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_schedule.example", + tfjsonpath.New("name"), + knownvalue.StringExact(prefix), + ), + statecheck.ExpectKnownValue( + "panos_schedule.example", + tfjsonpath.New("disable_override"), + knownvalue.StringExact("yes"), + ), + }, + }, + }, + }) +} + +const schedule_Basic_Tmpl = ` +variable "prefix" { type = string } +variable "location" { type = any } + +resource "panos_device_group" "example" { + location = { panorama = {} } + name = var.prefix +} + +resource "panos_schedule" "example" { + depends_on = [panos_device_group.example] + location = var.location + + name = var.prefix + disable_override = "yes" +} +` + +func TestAccSchedule_ScheduleType_NonRecurring(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(prefix), + }), + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: schedule_ScheduleType_NonRecurring_Tmpl, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + "location": location, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_schedule.example", + tfjsonpath.New("name"), + knownvalue.StringExact(prefix), + ), + statecheck.ExpectKnownValue( + "panos_schedule.example", + tfjsonpath.New("schedule_type"), + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "non_recurring": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.StringExact("2025/01/01@00:00-2025/01/31@23:59"), + knownvalue.StringExact("2025/12/24@00:00-2025/12/26@23:59"), + }), + "recurring": knownvalue.Null(), + }), + ), + }, + }, + }, + }) +} + +const schedule_ScheduleType_NonRecurring_Tmpl = ` +variable "prefix" { type = string } +variable "location" { type = any } + +resource "panos_device_group" "example" { + location = { panorama = {} } + name = var.prefix +} + +resource "panos_schedule" "example" { + depends_on = [panos_device_group.example] + location = var.location + + name = var.prefix + schedule_type = { + non_recurring = ["2025/01/01@00:00-2025/01/31@23:59", "2025/12/24@00:00-2025/12/26@23:59"] + } +} +` + +func TestAccSchedule_ScheduleType_Recurring_Daily(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(prefix), + }), + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: schedule_ScheduleType_Recurring_Daily_Tmpl, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + "location": location, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_schedule.example", + tfjsonpath.New("name"), + knownvalue.StringExact(prefix), + ), + statecheck.ExpectKnownValue( + "panos_schedule.example", + tfjsonpath.New("schedule_type"), + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "non_recurring": knownvalue.Null(), + "recurring": knownvalue.ObjectExact(map[string]knownvalue.Check{ + "daily": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.StringExact("09:00-17:00"), + knownvalue.StringExact("18:00-22:00"), + }), + "weekly": knownvalue.Null(), + }), + }), + ), + }, + }, + }, + }) +} + +const schedule_ScheduleType_Recurring_Daily_Tmpl = ` +variable "prefix" { type = string } +variable "location" { type = any } + +resource "panos_device_group" "example" { + location = { panorama = {} } + name = var.prefix +} + +resource "panos_schedule" "example" { + depends_on = [panos_device_group.example] + location = var.location + + name = var.prefix + schedule_type = { + recurring = { + daily = ["09:00-17:00", "18:00-22:00"] + } + } +} +` + +func TestAccSchedule_ScheduleType_Recurring_Weekly(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(prefix), + }), + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: schedule_ScheduleType_Recurring_Weekly_Tmpl, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + "location": location, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_schedule.example", + tfjsonpath.New("name"), + knownvalue.StringExact(prefix), + ), + statecheck.ExpectKnownValue( + "panos_schedule.example", + tfjsonpath.New("schedule_type"), + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "non_recurring": knownvalue.Null(), + "recurring": knownvalue.ObjectExact(map[string]knownvalue.Check{ + "daily": knownvalue.Null(), + "weekly": knownvalue.ObjectExact(map[string]knownvalue.Check{ + "monday": knownvalue.ListExact([]knownvalue.Check{knownvalue.StringExact("08:00-12:00"), knownvalue.StringExact("13:00-17:00")}), + "tuesday": knownvalue.ListExact([]knownvalue.Check{knownvalue.StringExact("08:00-12:00"), knownvalue.StringExact("13:00-17:00")}), + "wednesday": knownvalue.ListExact([]knownvalue.Check{knownvalue.StringExact("08:00-12:00"), knownvalue.StringExact("13:00-17:00")}), + "thursday": knownvalue.ListExact([]knownvalue.Check{knownvalue.StringExact("08:00-12:00"), knownvalue.StringExact("13:00-17:00")}), + "friday": knownvalue.ListExact([]knownvalue.Check{knownvalue.StringExact("08:00-12:00"), knownvalue.StringExact("13:00-17:00")}), + "saturday": knownvalue.ListExact([]knownvalue.Check{knownvalue.StringExact("10:00-14:00")}), + "sunday": knownvalue.ListExact([]knownvalue.Check{knownvalue.StringExact("10:00-14:00")}), + }), + }), + }), + ), + }, + }, + }, + }) +} + +const schedule_ScheduleType_Recurring_Weekly_Tmpl = ` +variable "prefix" { type = string } +variable "location" { type = any } + +resource "panos_device_group" "example" { + location = { panorama = {} } + name = var.prefix +} + +resource "panos_schedule" "example" { + depends_on = [panos_device_group.example] + location = var.location + + name = var.prefix + schedule_type = { + recurring = { + weekly = { + monday = ["08:00-12:00", "13:00-17:00"] + tuesday = ["08:00-12:00", "13:00-17:00"] + wednesday = ["08:00-12:00", "13:00-17:00"] + thursday = ["08:00-12:00", "13:00-17:00"] + friday = ["08:00-12:00", "13:00-17:00"] + saturday = ["10:00-14:00"] + sunday = ["10:00-14:00"] + } + } + } +} +` + +func TestAccSchedule_ScheduleType_Recurring_Weekly_SingleDay(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(prefix), + }), + }) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: schedule_ScheduleType_Recurring_Weekly_SingleDay_Tmpl, + ConfigVariables: map[string]config.Variable{ + "prefix": config.StringVariable(prefix), + "location": location, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue( + "panos_schedule.example", + tfjsonpath.New("name"), + knownvalue.StringExact(prefix), + ), + statecheck.ExpectKnownValue( + "panos_schedule.example", + tfjsonpath.New("schedule_type"), + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "non_recurring": knownvalue.Null(), + "recurring": knownvalue.ObjectExact(map[string]knownvalue.Check{ + "daily": knownvalue.Null(), + "weekly": knownvalue.ObjectExact(map[string]knownvalue.Check{ + "monday": knownvalue.ListExact([]knownvalue.Check{knownvalue.StringExact("09:00-17:00")}), + "tuesday": knownvalue.Null(), + "wednesday": knownvalue.Null(), + "thursday": knownvalue.Null(), + "friday": knownvalue.Null(), + "saturday": knownvalue.Null(), + "sunday": knownvalue.Null(), + }), + }), + }), + ), + }, + }, + }, + }) +} + +const schedule_ScheduleType_Recurring_Weekly_SingleDay_Tmpl = ` +variable "prefix" { type = string } +variable "location" { type = any } + +resource "panos_device_group" "example" { + location = { panorama = {} } + name = var.prefix +} + +resource "panos_schedule" "example" { + depends_on = [panos_device_group.example] + location = var.location + + name = var.prefix + schedule_type = { + recurring = { + weekly = { + monday = ["09:00-17:00"] + } + } + } +} +` diff --git a/specs/objects/schedule.yaml b/specs/objects/schedule.yaml new file mode 100644 index 00000000..dc6575a8 --- /dev/null +++ b/specs/objects/schedule.yaml @@ -0,0 +1,275 @@ +name: schedule +terraform_provider_config: + description: Schedule Object + skip_resource: false + skip_datasource: false + resource_type: entry + resource_variants: + - singular + suffix: schedule + plural_suffix: '' + plural_name: '' + plural_description: '' +go_sdk_config: + skip: false + package: + - objects + - schedules +panos_xpath: + path: + - schedule + vars: [] +locations: +- name: shared + xpath: + path: + - config + - shared + vars: [] + description: Panorama shared object + devices: + - panorama + - ngfw + validators: [] + required: false + read_only: false +- name: vsys + xpath: + path: + - config + - devices + - $ngfw_device + - vsys + - $vsys + vars: + - name: ngfw_device + description: The NGFW device name + required: false + default: localhost.localdomain + validators: [] + type: entry + - name: vsys + description: The Virtual System name + required: false + default: vsys1 + validators: + - type: not-values + spec: + values: + - value: shared + error: The vsys name cannot be "shared". Use the "shared" location instead + type: entry + description: Located in a specific Virtual System + devices: + - 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 + location_filter: true + description: Located in a specific Device Group + devices: + - panorama + validators: [] + required: false + read_only: false +entries: +- name: name + description: '' + validators: [] +spec: + params: + - 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: schedule-type + type: object + profiles: + - xpath: + - schedule-type + validators: [] + spec: + params: [] + variants: + - name: non-recurring + type: list + profiles: + - xpath: + - non-recurring + type: member + validators: [] + spec: + type: string + items: + type: string + description: '' + required: false + - name: recurring + type: object + profiles: + - xpath: + - recurring + validators: [] + spec: + params: [] + variants: + - name: daily + type: list + profiles: + - xpath: + - daily + type: member + validators: [] + spec: + type: string + items: + type: string + description: '' + required: false + - name: weekly + type: object + profiles: + - xpath: + - weekly + validators: [] + spec: + params: + - name: friday + type: list + profiles: + - xpath: + - friday + type: member + validators: [] + spec: + type: string + items: + type: string + description: '' + required: false + - name: monday + type: list + profiles: + - xpath: + - monday + type: member + validators: [] + spec: + type: string + items: + type: string + description: '' + required: false + - name: saturday + type: list + profiles: + - xpath: + - saturday + type: member + validators: [] + spec: + type: string + items: + type: string + description: '' + required: false + - name: sunday + type: list + profiles: + - xpath: + - sunday + type: member + validators: [] + spec: + type: string + items: + type: string + description: '' + required: false + - name: thursday + type: list + profiles: + - xpath: + - thursday + type: member + validators: [] + spec: + type: string + items: + type: string + description: '' + required: false + - name: tuesday + type: list + profiles: + - xpath: + - tuesday + type: member + validators: [] + spec: + type: string + items: + type: string + description: '' + required: false + - name: wednesday + type: list + profiles: + - xpath: + - wednesday + type: member + validators: [] + spec: + type: string + items: + type: string + description: '' + required: false + variants: [] + description: '' + required: false + description: '' + required: false + description: '' + required: false + variants: []