@@ -2,18 +2,21 @@ package provider
22
33import (
44 "context"
5+ "encoding/json"
56 "fmt"
67 "strings"
78
89 "github.com/segmentio/terraform-provider-segment/internal/provider/docs"
910 "github.com/segmentio/terraform-provider-segment/internal/provider/models"
1011
1112 "github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes"
13+ "github.com/hashicorp/terraform-plugin-framework/diag"
1214 "github.com/hashicorp/terraform-plugin-framework/path"
1315 "github.com/hashicorp/terraform-plugin-framework/resource"
1416 "github.com/hashicorp/terraform-plugin-framework/resource/schema"
1517 "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
1618 "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
19+ "github.com/hashicorp/terraform-plugin-framework/types/basetypes"
1720
1821 "github.com/segmentio/public-api-sdk-go/api"
1922)
@@ -91,12 +94,27 @@ func (r *destinationSubscriptionResource) Schema(_ context.Context, _ resource.S
9194 Description : `The customer settings for action fields. Only settings included in the configuration will be managed by Terraform.` ,
9295 CustomType : jsontypes.NormalizedType {},
9396 },
97+ "reverse_etl_schedule" : schema.SingleNestedAttribute {
98+ Optional : true ,
99+ Description : "(Reverse ETL only) The schedule for the subscription being attached to ReverseETL model." ,
100+ Attributes : map [string ]schema.Attribute {
101+ "strategy" : schema.StringAttribute {
102+ Required : true ,
103+ Description : "Strategy supports three modes: PERIODIC, SPECIFIC_DAYS, or MANUAL." ,
104+ },
105+ "config" : schema.StringAttribute {
106+ Optional : true ,
107+ Description : "Configures the schedule for the subscription." ,
108+ CustomType : jsontypes.NormalizedType {},
109+ },
110+ },
111+ },
94112 },
95113 }
96114}
97115
98116func (r * destinationSubscriptionResource ) Create (ctx context.Context , req resource.CreateRequest , resp * resource.CreateResponse ) {
99- var plan models.DestinationSubscriptionState
117+ var plan models.DestinationSubscriptionPlan
100118 diags := req .Plan .Get (ctx , & plan )
101119 resp .Diagnostics .Append (diags ... )
102120 if resp .Diagnostics .HasError () {
@@ -110,6 +128,15 @@ func (r *destinationSubscriptionResource) Create(ctx context.Context, req resour
110128 return
111129 }
112130
131+ if ! plan .ModelID .IsNull () && ! plan .ModelID .IsUnknown () && (plan .ReverseETLSchedule .IsNull () || plan .ReverseETLSchedule .IsUnknown ()) {
132+ resp .Diagnostics .AddError (
133+ "Reverse ETL model ID provided without reverse ETL schedule" ,
134+ "Reverse ETL model ID must be provided with a reverse ETL schedule" ,
135+ )
136+
137+ return
138+ }
139+
113140 out , body , err := r .client .DestinationsAPI .CreateDestinationSubscription (r .authContext , plan .DestinationID .ValueString ()).CreateDestinationSubscriptionAlphaInput (api.CreateDestinationSubscriptionAlphaInput {
114141 Name : plan .Name .ValueString (),
115142 ActionId : plan .ActionID .ValueString (),
@@ -130,9 +157,39 @@ func (r *destinationSubscriptionResource) Create(ctx context.Context, req resour
130157 return
131158 }
132159
133- destinationSubscription := out .Data .GetDestinationSubscription ()
160+ resp .State .SetAttribute (ctx , path .Root ("id" ), out .Data .DestinationSubscription .Id )
161+ resp .State .SetAttribute (ctx , path .Root ("destination_id" ), out .Data .DestinationSubscription .DestinationId )
162+
163+ reverseETLSchedule , diags := getSchedule (ctx , plan .ReverseETLSchedule )
164+ if diags .HasError () {
165+ resp .Diagnostics .Append (diags ... )
166+
167+ return
168+ }
169+
170+ updateOut , body , err := r .client .DestinationsAPI .UpdateSubscriptionForDestination (r .authContext , plan .DestinationID .ValueString (), out .Data .DestinationSubscription .Id ).UpdateSubscriptionForDestinationAlphaInput (api.UpdateSubscriptionForDestinationAlphaInput {
171+ Input : api.DestinationSubscriptionUpdateInput {
172+ Name : plan .Name .ValueStringPointer (),
173+ Trigger : plan .Trigger .ValueStringPointer (),
174+ Enabled : plan .Enabled .ValueBoolPointer (),
175+ Settings : settings ,
176+ ReverseETLModelId : plan .ModelID .ValueStringPointer (),
177+ ReverseETLSchedule : reverseETLSchedule ,
178+ },
179+ }).Execute ()
180+ if body != nil {
181+ defer body .Body .Close ()
182+ }
183+ if err != nil {
184+ resp .Diagnostics .AddError (
185+ "Unable to update Destination subscription" ,
186+ getError (err , body ),
187+ )
188+
189+ return
190+ }
134191
135- resp . State . SetAttribute ( ctx , path . Root ( "id" ), destinationSubscription . Id )
192+ destinationSubscription := updateOut . Data . Subscription
136193
137194 var state models.DestinationSubscriptionState
138195 err = state .Fill (destinationSubscription )
@@ -203,7 +260,7 @@ func (r *destinationSubscriptionResource) Read(ctx context.Context, req resource
203260}
204261
205262func (r * destinationSubscriptionResource ) Update (ctx context.Context , req resource.UpdateRequest , resp * resource.UpdateResponse ) {
206- var plan models.DestinationSubscriptionState
263+ var plan models.DestinationSubscriptionPlan
207264 diags := req .Plan .Get (ctx , & plan )
208265 resp .Diagnostics .Append (diags ... )
209266 if resp .Diagnostics .HasError () {
@@ -224,12 +281,30 @@ func (r *destinationSubscriptionResource) Update(ctx context.Context, req resour
224281 return
225282 }
226283
284+ if ! plan .ModelID .IsNull () && ! plan .ModelID .IsUnknown () && (plan .ReverseETLSchedule .IsNull () || plan .ReverseETLSchedule .IsUnknown ()) {
285+ resp .Diagnostics .AddError (
286+ "Reverse ETL model ID provided without reverse ETL schedule" ,
287+ "Reverse ETL model ID must be provided with a reverse ETL schedule" ,
288+ )
289+
290+ return
291+ }
292+
293+ reverseETLSchedule , diags := getSchedule (ctx , plan .ReverseETLSchedule )
294+ if diags .HasError () {
295+ resp .Diagnostics .Append (diags ... )
296+
297+ return
298+ }
299+
227300 out , body , err := r .client .DestinationsAPI .UpdateSubscriptionForDestination (r .authContext , state .DestinationID .ValueString (), state .ID .ValueString ()).UpdateSubscriptionForDestinationAlphaInput (api.UpdateSubscriptionForDestinationAlphaInput {
228301 Input : api.DestinationSubscriptionUpdateInput {
229- Name : plan .Name .ValueStringPointer (),
230- Trigger : plan .Trigger .ValueStringPointer (),
231- Enabled : plan .Enabled .ValueBoolPointer (),
232- Settings : settings ,
302+ Name : plan .Name .ValueStringPointer (),
303+ Trigger : plan .Trigger .ValueStringPointer (),
304+ Enabled : plan .Enabled .ValueBoolPointer (),
305+ Settings : settings ,
306+ ReverseETLModelId : plan .ModelID .ValueStringPointer (),
307+ ReverseETLSchedule : reverseETLSchedule ,
233308 },
234309 }).Execute ()
235310 if body != nil {
@@ -320,3 +395,115 @@ func (r *destinationSubscriptionResource) Configure(_ context.Context, req resou
320395 r .client = config .client
321396 r .authContext = config .authContext
322397}
398+
399+ func getSchedule (ctx context.Context , planSchedule basetypes.ObjectValue ) (* api.ReverseEtlScheduleDefinition , diag.Diagnostics ) {
400+ var reverseETLSchedule * api.ReverseEtlScheduleDefinition
401+ var diags diag.Diagnostics
402+ if ! planSchedule .IsNull () && ! planSchedule .IsUnknown () {
403+ reverseETLSchedule = & api.ReverseEtlScheduleDefinition {}
404+
405+ wrappedReverseETLModelScheduleStrategy , err := planSchedule .Attributes ()["strategy" ].ToTerraformValue (ctx )
406+ if err != nil {
407+ diags .AddError (
408+ "Unable to decode reverse ETL schedule strategy" ,
409+ err .Error (),
410+ )
411+
412+ return nil , diags
413+ }
414+
415+ var reverseETLModelScheduleStrategy string
416+ err = wrappedReverseETLModelScheduleStrategy .As (& reverseETLModelScheduleStrategy )
417+ if err != nil {
418+ diags .AddError (
419+ "Unable to decode reverse ETL schedule strategy" ,
420+ err .Error (),
421+ )
422+
423+ return nil , diags
424+ }
425+
426+ reverseETLSchedule .Strategy = reverseETLModelScheduleStrategy
427+
428+ wrappedReverseETLModelScheduleConfig , err := planSchedule .Attributes ()["config" ].ToTerraformValue (ctx )
429+ if err != nil {
430+ diags .AddError (
431+ "Unable to decode reverse ETL schedule config" ,
432+ err .Error (),
433+ )
434+
435+ return nil , diags
436+ }
437+
438+ if ! wrappedReverseETLModelScheduleConfig .IsNull () && wrappedReverseETLModelScheduleConfig .IsKnown () {
439+ if reverseETLSchedule .Strategy == "PERIODIC" {
440+ reverseETLModelScheduleConfig := api.ReverseEtlPeriodicScheduleConfig {}
441+ var config string
442+ err = wrappedReverseETLModelScheduleConfig .As (& config )
443+ if err != nil {
444+ diags .AddError (
445+ "Unable to decode reverse ETL schedule config" ,
446+ err .Error (),
447+ )
448+
449+ return nil , diags
450+ }
451+
452+ err = json .Unmarshal ([]byte (config ), & reverseETLModelScheduleConfig )
453+ if err != nil {
454+ diags .AddError (
455+ "Unable to decode reverse ETL schedule config" ,
456+ err .Error (),
457+ )
458+
459+ return nil , diags
460+ }
461+
462+ reverseETLSchedule .Config = * api .NewNullableConfig (& api.Config {
463+ ReverseEtlPeriodicScheduleConfig : & reverseETLModelScheduleConfig ,
464+ })
465+ } else if reverseETLSchedule .Strategy == "SPECIFIC_DAYS" {
466+ reverseETLModelScheduleConfig := api.ReverseEtlSpecificTimeScheduleConfig {}
467+ var config string
468+ err = wrappedReverseETLModelScheduleConfig .As (& config )
469+ if err != nil {
470+ diags .AddError (
471+ "Unable to decode reverse ETL schedule config" ,
472+ err .Error (),
473+ )
474+
475+ return nil , diags
476+ }
477+
478+ err = json .Unmarshal ([]byte (config ), & reverseETLModelScheduleConfig )
479+ if err != nil {
480+ diags .AddError (
481+ "Unable to decode reverse ETL schedule config" ,
482+ err .Error (),
483+ )
484+
485+ return nil , diags
486+ }
487+
488+ reverseETLSchedule .Config = * api .NewNullableConfig (& api.Config {
489+ ReverseEtlSpecificTimeScheduleConfig : & reverseETLModelScheduleConfig ,
490+ })
491+ } else if reverseETLSchedule .Strategy == "MANUAL" {
492+ diags .AddError (
493+ "Manual reverse ETL schedule strategy does not require a config" ,
494+ "Manual reverse ETL schedule strategy does not require a config" ,
495+ )
496+ reverseETLSchedule .Config = * api .NewNullableConfig (nil )
497+ } else {
498+ diags .AddError (
499+ "Unsupported reverse ETL schedule strategy" ,
500+ fmt .Sprintf ("Strategy %q is not supported" , reverseETLSchedule .Strategy ),
501+ )
502+
503+ return nil , diags
504+ }
505+ }
506+ }
507+
508+ return reverseETLSchedule , diags
509+ }
0 commit comments