diff --git a/docs/resources/scheduled_report.md b/docs/resources/scheduled_report.md new file mode 100644 index 0000000..1cbeb5b --- /dev/null +++ b/docs/resources/scheduled_report.md @@ -0,0 +1,38 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "uptime_scheduled_report Resource - terraform-provider-uptime" +subcategory: "" +description: |- + +--- + +# uptime_scheduled_report (Resource) + + + + + + +## Schema + +### Required + +- `name` (String) +- `sla_report` (String) Select an SLA report to send on this schedule + +### Optional + +- `at_time` (Number) Reports will be sent at this time (local time), value is hour of day: 0-23 +- `file_type` (String) Report file type, valid values are PDF(default) or XLS +- `is_enabled` (Boolean) +- `on_weekday` (Number) Weekly reports will be sent on this day +- `recipient_emails` (Set of String) +- `recipient_users` (Set of String) +- `recurrence` (String) How often to deliver this report. Valid values are DAILY, WEEKLY, MONTHLY, QUARTERLY, YEARLY + +### Read-Only + +- `id` (Number) The ID of this resource. +- `url` (String) + + diff --git a/go.mod b/go.mod index 262587d..fe5b8fe 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/shopspring/decimal v1.4.0 github.com/stretchr/testify v1.9.0 - github.com/uptime-com/uptime-client-go/v2 v2.0.0-20240829075731-38b4feeffc12 + github.com/uptime-com/uptime-client-go/v2 v2.0.0-20240909144813-ed02ddd58c28 ) require ( diff --git a/go.sum b/go.sum index 9fe0b9d..2da98db 100644 --- a/go.sum +++ b/go.sum @@ -163,6 +163,10 @@ github.com/uptime-com/uptime-client-go/v2 v2.0.0-20240826143229-a0300708e548 h1: github.com/uptime-com/uptime-client-go/v2 v2.0.0-20240826143229-a0300708e548/go.mod h1:jtWeB/tQ00fLX2r9OwKfTnxQ/PMR0YjmhTuc9RZH2h0= github.com/uptime-com/uptime-client-go/v2 v2.0.0-20240829075731-38b4feeffc12 h1:4EwfHypfh6BxyUYTcVwccp+YPvqshl4klonwhK9ssO4= github.com/uptime-com/uptime-client-go/v2 v2.0.0-20240829075731-38b4feeffc12/go.mod h1:jtWeB/tQ00fLX2r9OwKfTnxQ/PMR0YjmhTuc9RZH2h0= +github.com/uptime-com/uptime-client-go/v2 v2.0.0-20240909143903-2201e1ed51bd h1:CPhzpLzR8yQxk4TwQ4NmqzeEV/MJkFYFI9b6lVXxIhM= +github.com/uptime-com/uptime-client-go/v2 v2.0.0-20240909143903-2201e1ed51bd/go.mod h1:jtWeB/tQ00fLX2r9OwKfTnxQ/PMR0YjmhTuc9RZH2h0= +github.com/uptime-com/uptime-client-go/v2 v2.0.0-20240909144813-ed02ddd58c28 h1:m8H8Q1ZXZEZQk74afxryN2NuRLuMEWi6oB/KjAl7evU= +github.com/uptime-com/uptime-client-go/v2 v2.0.0-20240909144813-ed02ddd58c28/go.mod h1:jtWeB/tQ00fLX2r9OwKfTnxQ/PMR0YjmhTuc9RZH2h0= github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= diff --git a/internal/provider/provider.go b/internal/provider/provider.go index f0fd66e..539e896 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -133,6 +133,7 @@ func (p *providerImpl) Resources(ctx context.Context) []func() resource.Resource func() resource.Resource { return NewSLAReportResource(ctx, p) }, func() resource.Resource { return NewDashboardResource(ctx, p) }, func() resource.Resource { return NewTagResource(ctx, p) }, + func() resource.Resource { return NewScheduledReportResource(ctx, p) }, } } diff --git a/internal/provider/resource_scheduledreport.go b/internal/provider/resource_scheduledreport.go new file mode 100644 index 0000000..1283cf6 --- /dev/null +++ b/internal/provider/resource_scheduledreport.go @@ -0,0 +1,178 @@ +package provider + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework-validators/int32validator" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/int32default" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/setdefault" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/uptime-com/uptime-client-go/v2/pkg/upapi" +) + +func NewScheduledReportResource(_ context.Context, p *providerImpl) resource.Resource { + return APIResource[ScheduledReportResourceModel, upapi.ScheduledReport, upapi.ScheduledReport]{ + api: &ScheduledReportResourceAPI{provider: p}, + mod: ScheduledReportResourceModelAdapter{}, + meta: APIResourceMetadata{ + TypeNameSuffix: "scheduled_report", + Schema: schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": IDSchemaAttribute(), + "url": URLSchemaAttribute(), + "name": NameSchemaAttribute(), + "sla_report": schema.StringAttribute{ + Required: true, + Description: "Select an SLA report to send on this schedule", + }, + "recipient_users": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + Computed: true, + Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})), + }, + "recipient_emails": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + Computed: true, + Default: setdefault.StaticValue(types.SetValueMust(types.StringType, []attr.Value{})), + }, + "file_type": schema.StringAttribute{ + Optional: true, + Computed: true, + Default: stringdefault.StaticString("PDF"), + Description: "Report file type, valid values are PDF(default) or XLS", + Validators: []validator.String{ + OneOfStringValidator([]string{"PDF", "XLS"}), + }, + }, + "recurrence": schema.StringAttribute{ + Optional: true, + Computed: true, + Default: stringdefault.StaticString("DAILY"), + Description: "How often to deliver this report. Valid values are DAILY, WEEKLY, MONTHLY, QUARTERLY, YEARLY", + Validators: []validator.String{ + OneOfStringValidator([]string{"DAILY", "WEEKLY", "MONTHLY", "QUARTERLY", "YEARLY"}), + }, + }, + "on_weekday": schema.Int32Attribute{ + Optional: true, + Computed: true, + Default: int32default.StaticInt32(1), + Description: "Weekly reports will be sent on this day", + Validators: []validator.Int32{ + int32validator.Between(1, 7), + }, + }, + "at_time": schema.Int32Attribute{ + Optional: true, + Computed: true, + Default: int32default.StaticInt32(1), + Description: "Reports will be sent at this time (local time), value is hour of day: 0-23", + Validators: []validator.Int32{ + int32validator.Between(0, 23), + }, + }, + "is_enabled": schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(true), + }, + }, + }, + }, + } +} + +type ScheduledReportResourceModel struct { + ID types.Int64 `tfsdk:"id"` + URL types.String `tfsdk:"url"` + Name types.String `tfsdk:"name"` + ScheduledReport types.String `tfsdk:"sla_report"` + RecipientUsers types.Set `tfsdk:"recipient_users"` + RecipientEmails types.Set `tfsdk:"recipient_emails"` + FileType types.String `tfsdk:"file_type"` + Recurrence types.String `tfsdk:"recurrence"` + OnWeekday types.Int32 `tfsdk:"on_weekday"` + AtTime types.Int32 `tfsdk:"at_time"` + IsEnabled types.Bool `tfsdk:"is_enabled"` +} + +func (m ScheduledReportResourceModel) PrimaryKey() upapi.PrimaryKey { + return upapi.PrimaryKey(m.ID.ValueInt64()) +} + +type ScheduledReportResourceModelAdapter struct { + TagsAttributeAdapter + SetAttributeAdapter[string] +} + +func (a ScheduledReportResourceModelAdapter) Get(ctx context.Context, sg StateGetter) (*ScheduledReportResourceModel, diag.Diagnostics) { + model := *new(ScheduledReportResourceModel) + diags := sg.Get(ctx, &model) + if diags.HasError() { + return nil, diags + } + return &model, nil +} + +func (a ScheduledReportResourceModelAdapter) ToAPIArgument(model ScheduledReportResourceModel) (*upapi.ScheduledReport, error) { + return &upapi.ScheduledReport{ + Name: model.Name.ValueString(), + ScheduledReport: model.ScheduledReport.ValueString(), + RecipientUsers: a.Slice(model.RecipientUsers), + RecipientEmails: a.Slice(model.RecipientEmails), + FileType: model.FileType.ValueString(), + Recurrence: model.Recurrence.ValueString(), + OnWeekday: model.OnWeekday.ValueInt32(), + AtTime: model.AtTime.ValueInt32(), + IsEnabled: model.IsEnabled.ValueBool(), + }, nil +} + +func (a ScheduledReportResourceModelAdapter) FromAPIResult(api upapi.ScheduledReport) (*ScheduledReportResourceModel, error) { + return &ScheduledReportResourceModel{ + ID: types.Int64Value(api.PK), + URL: types.StringValue(api.URL), + Name: types.StringValue(api.Name), + ScheduledReport: types.StringValue(api.ScheduledReport), + RecipientUsers: a.SliceValue(api.RecipientUsers), + RecipientEmails: a.SliceValue(api.RecipientEmails), + FileType: types.StringValue(api.FileType), + Recurrence: types.StringValue(api.Recurrence), + OnWeekday: types.Int32Value(int32(api.OnWeekday)), + AtTime: types.Int32Value(int32(api.AtTime)), + IsEnabled: types.BoolValue(api.IsEnabled), + }, nil +} + +type ScheduledReportResourceAPI struct { + provider *providerImpl +} + +func (a ScheduledReportResourceAPI) Create(ctx context.Context, arg upapi.ScheduledReport) (*upapi.ScheduledReport, error) { + obj, err := a.provider.api.ScheduledReports().Create(ctx, arg) + if err != nil { + return nil, err + } + return obj, nil +} + +func (a ScheduledReportResourceAPI) Read(ctx context.Context, arg upapi.PrimaryKeyable) (*upapi.ScheduledReport, error) { + return a.provider.api.ScheduledReports().Get(ctx, arg) +} + +func (a ScheduledReportResourceAPI) Update(ctx context.Context, pk upapi.PrimaryKeyable, arg upapi.ScheduledReport) (*upapi.ScheduledReport, error) { + return a.provider.api.ScheduledReports().Update(ctx, pk, arg) +} + +func (a ScheduledReportResourceAPI) Delete(ctx context.Context, keyable upapi.PrimaryKeyable) error { + return a.provider.api.ScheduledReports().Delete(ctx, keyable) +} diff --git a/internal/provider/resource_scheduledreport_test.go b/internal/provider/resource_scheduledreport_test.go new file mode 100644 index 0000000..26e8d46 --- /dev/null +++ b/internal/provider/resource_scheduledreport_test.go @@ -0,0 +1,187 @@ +package provider + +import ( + "testing" + + petname "github.com/dustinkirkland/golang-petname" + "github.com/hashicorp/terraform-plugin-testing/config" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestAccScheduledReportResource_Basic(t *testing.T) { + name := petname.Generate(3, "-") + sla_report_name := petname.Generate(3, "-") + resource.Test(t, testCaseFromSteps(t, []resource.TestStep{ + { + ConfigVariables: config.Variables{ + "name": config.StringVariable(name), + "sla_report_name": config.StringVariable(sla_report_name), + }, + ConfigDirectory: config.StaticDirectory("testdata/resource_scheduledreport/_basic"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("uptime_scheduled_report.test", "name", name), + resource.TestCheckResourceAttr("uptime_scheduled_report.test", "sla_report", sla_report_name), + ), + }, + })) +} + +func TestAccScheduledReportResource_RecipientEmails(t *testing.T) { + name := petname.Generate(3, "-") + sla_report_name := petname.Generate(3, "-") + emails := make([]string, 3) + for i := range emails { + emails[i] = petname.Generate(2, "@") + ".com" + } + resource.Test(t, testCaseFromSteps(t, []resource.TestStep{ + { + ConfigVariables: config.Variables{ + "name": config.StringVariable(name), + "sla_report_name": config.StringVariable(sla_report_name), + "recipient_emails": config.SetVariable( + config.StringVariable(emails[0]), + config.StringVariable(emails[1]), + config.StringVariable(emails[2]), + ), + }, + ConfigDirectory: config.StaticDirectory("testdata/resource_scheduledreport/recipient_emails"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("uptime_scheduled_report.test", "name", name), + resource.TestCheckResourceAttr("uptime_scheduled_report.test", "sla_report", sla_report_name), + resource.TestCheckResourceAttr("uptime_scheduled_report.test", "recipient_emails.#", "3"), + ), + }, + })) +} + +func TestAccScheduledReportResource_FileType(t *testing.T) { + name := petname.Generate(3, "-") + sla_report_name := petname.Generate(3, "-") + resource.Test(t, testCaseFromSteps(t, []resource.TestStep{ + { + ConfigVariables: config.Variables{ + "name": config.StringVariable(name), + "sla_report_name": config.StringVariable(sla_report_name), + "file_type": config.StringVariable("PDF"), + }, + ConfigDirectory: config.StaticDirectory("testdata/resource_scheduledreport/file_type"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("uptime_scheduled_report.test", "name", name), + resource.TestCheckResourceAttr("uptime_scheduled_report.test", "sla_report", sla_report_name), + resource.TestCheckResourceAttr("uptime_scheduled_report.test", "file_type", "PDF"), + ), + }, + { + ConfigVariables: config.Variables{ + "name": config.StringVariable(name), + "sla_report_name": config.StringVariable(sla_report_name), + "file_type": config.StringVariable("XLS"), + }, + ConfigDirectory: config.StaticDirectory("testdata/resource_scheduledreport/file_type"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("uptime_scheduled_report.test", "name", name), + resource.TestCheckResourceAttr("uptime_scheduled_report.test", "sla_report", sla_report_name), + resource.TestCheckResourceAttr("uptime_scheduled_report.test", "file_type", "XLS"), + ), + }, + })) +} + +func TestAccScheduledReportResource_Recurrence(t *testing.T) { + name := petname.Generate(3, "-") + sla_report_name := petname.Generate(3, "-") + resource.Test(t, testCaseFromSteps(t, []resource.TestStep{ + { + ConfigVariables: config.Variables{ + "name": config.StringVariable(name), + "sla_report_name": config.StringVariable(sla_report_name), + "recurrence": config.StringVariable("DAILY"), + }, + ConfigDirectory: config.StaticDirectory("testdata/resource_scheduledreport/recurrence"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("uptime_scheduled_report.test", "name", name), + resource.TestCheckResourceAttr("uptime_scheduled_report.test", "sla_report", sla_report_name), + resource.TestCheckResourceAttr("uptime_scheduled_report.test", "recurrence", "DAILY"), + ), + }, + { + ConfigVariables: config.Variables{ + "name": config.StringVariable(name), + "sla_report_name": config.StringVariable(sla_report_name), + "recurrence": config.StringVariable("QUARTERLY"), + }, + ConfigDirectory: config.StaticDirectory("testdata/resource_scheduledreport/recurrence"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("uptime_scheduled_report.test", "name", name), + resource.TestCheckResourceAttr("uptime_scheduled_report.test", "sla_report", sla_report_name), + resource.TestCheckResourceAttr("uptime_scheduled_report.test", "recurrence", "QUARTERLY"), + ), + }, + })) +} + +func TestAccScheduledReportResource_OnWeekday(t *testing.T) { + name := petname.Generate(3, "-") + sla_report_name := petname.Generate(3, "-") + resource.Test(t, testCaseFromSteps(t, []resource.TestStep{ + { + ConfigVariables: config.Variables{ + "name": config.StringVariable(name), + "sla_report_name": config.StringVariable(sla_report_name), + "on_weekday": config.IntegerVariable(1), + }, + ConfigDirectory: config.StaticDirectory("testdata/resource_scheduledreport/on_weekday"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("uptime_scheduled_report.test", "name", name), + resource.TestCheckResourceAttr("uptime_scheduled_report.test", "sla_report", sla_report_name), + resource.TestCheckResourceAttr("uptime_scheduled_report.test", "on_weekday", "1"), + ), + }, + { + ConfigVariables: config.Variables{ + "name": config.StringVariable(name), + "sla_report_name": config.StringVariable(sla_report_name), + "on_weekday": config.IntegerVariable(7), + }, + ConfigDirectory: config.StaticDirectory("testdata/resource_scheduledreport/on_weekday"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("uptime_scheduled_report.test", "name", name), + resource.TestCheckResourceAttr("uptime_scheduled_report.test", "sla_report", sla_report_name), + resource.TestCheckResourceAttr("uptime_scheduled_report.test", "on_weekday", "7"), + ), + }, + })) +} + +func TestAccScheduledReportResource_AtTime(t *testing.T) { + name := petname.Generate(3, "-") + sla_report_name := petname.Generate(3, "-") + resource.Test(t, testCaseFromSteps(t, []resource.TestStep{ + { + ConfigVariables: config.Variables{ + "name": config.StringVariable(name), + "sla_report_name": config.StringVariable(sla_report_name), + "at_time": config.IntegerVariable(0), + }, + ConfigDirectory: config.StaticDirectory("testdata/resource_scheduledreport/at_time"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("uptime_scheduled_report.test", "name", name), + resource.TestCheckResourceAttr("uptime_scheduled_report.test", "sla_report", sla_report_name), + resource.TestCheckResourceAttr("uptime_scheduled_report.test", "at_time", "0"), + ), + }, + { + ConfigVariables: config.Variables{ + "name": config.StringVariable(name), + "sla_report_name": config.StringVariable(sla_report_name), + "at_time": config.IntegerVariable(23), + }, + ConfigDirectory: config.StaticDirectory("testdata/resource_scheduledreport/at_time"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("uptime_scheduled_report.test", "name", name), + resource.TestCheckResourceAttr("uptime_scheduled_report.test", "sla_report", sla_report_name), + resource.TestCheckResourceAttr("uptime_scheduled_report.test", "at_time", "23"), + ), + }, + })) +} diff --git a/internal/provider/testdata/resource_scheduledreport/_basic/main.tf b/internal/provider/testdata/resource_scheduledreport/_basic/main.tf new file mode 100644 index 0000000..e947343 --- /dev/null +++ b/internal/provider/testdata/resource_scheduledreport/_basic/main.tf @@ -0,0 +1,17 @@ +variable "name" { + type = string +} + +variable "sla_report_name" { + type = string +} + +resource "uptime_sla_report" "test" { + name = var.sla_report_name +} + +resource "uptime_scheduled_report" "test" { + depends_on = [uptime_sla_report.test] + name = var.name + sla_report = var.sla_report_name +} diff --git a/internal/provider/testdata/resource_scheduledreport/at_time/main.tf b/internal/provider/testdata/resource_scheduledreport/at_time/main.tf new file mode 100644 index 0000000..be78323 --- /dev/null +++ b/internal/provider/testdata/resource_scheduledreport/at_time/main.tf @@ -0,0 +1,22 @@ +variable "name" { + type = string +} + +variable "sla_report_name" { + type = string +} + +variable "at_time" { + type = number +} + +resource "uptime_sla_report" "test" { + name = var.sla_report_name +} + +resource "uptime_scheduled_report" "test" { + depends_on = [uptime_sla_report.test] + name = var.name + sla_report = var.sla_report_name + at_time = var.at_time +} diff --git a/internal/provider/testdata/resource_scheduledreport/file_type/main.tf b/internal/provider/testdata/resource_scheduledreport/file_type/main.tf new file mode 100644 index 0000000..f83b960 --- /dev/null +++ b/internal/provider/testdata/resource_scheduledreport/file_type/main.tf @@ -0,0 +1,22 @@ +variable "name" { + type = string +} + +variable "sla_report_name" { + type = string +} + +variable "file_type" { + type = string +} + +resource "uptime_sla_report" "test" { + name = var.sla_report_name +} + +resource "uptime_scheduled_report" "test" { + depends_on = [uptime_sla_report.test] + name = var.name + sla_report = var.sla_report_name + file_type = var.file_type +} diff --git a/internal/provider/testdata/resource_scheduledreport/on_weekday/main.tf b/internal/provider/testdata/resource_scheduledreport/on_weekday/main.tf new file mode 100644 index 0000000..eda092c --- /dev/null +++ b/internal/provider/testdata/resource_scheduledreport/on_weekday/main.tf @@ -0,0 +1,22 @@ +variable "name" { + type = string +} + +variable "sla_report_name" { + type = string +} + +variable "on_weekday" { + type = number +} + +resource "uptime_sla_report" "test" { + name = var.sla_report_name +} + +resource "uptime_scheduled_report" "test" { + depends_on = [uptime_sla_report.test] + name = var.name + sla_report = var.sla_report_name + on_weekday = var.on_weekday +} diff --git a/internal/provider/testdata/resource_scheduledreport/recipient_emails/main.tf b/internal/provider/testdata/resource_scheduledreport/recipient_emails/main.tf new file mode 100644 index 0000000..2b16f15 --- /dev/null +++ b/internal/provider/testdata/resource_scheduledreport/recipient_emails/main.tf @@ -0,0 +1,22 @@ +variable "name" { + type = string +} + +variable "sla_report_name" { + type = string +} + +variable "recipient_emails" { + type = set(string) +} + +resource "uptime_sla_report" "test" { + name = var.sla_report_name +} + +resource "uptime_scheduled_report" "test" { + depends_on = [uptime_sla_report.test] + name = var.name + sla_report = var.sla_report_name + recipient_emails = var.recipient_emails +} diff --git a/internal/provider/testdata/resource_scheduledreport/recurrence/main.tf b/internal/provider/testdata/resource_scheduledreport/recurrence/main.tf new file mode 100644 index 0000000..68c55e4 --- /dev/null +++ b/internal/provider/testdata/resource_scheduledreport/recurrence/main.tf @@ -0,0 +1,22 @@ +variable "name" { + type = string +} + +variable "sla_report_name" { + type = string +} + +variable "recurrence" { + type = string +} + +resource "uptime_sla_report" "test" { + name = var.sla_report_name +} + +resource "uptime_scheduled_report" "test" { + depends_on = [uptime_sla_report.test] + name = var.name + sla_report = var.sla_report_name + recurrence = var.recurrence +}