@@ -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,38 @@ 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+ return
167+ }
168+
169+ updateOut , body , err := r .client .DestinationsAPI .UpdateSubscriptionForDestination (r .authContext , plan .DestinationID .ValueString (), out .Data .DestinationSubscription .Id ).UpdateSubscriptionForDestinationAlphaInput (api.UpdateSubscriptionForDestinationAlphaInput {
170+ Input : api.DestinationSubscriptionUpdateInput {
171+ Name : plan .Name .ValueStringPointer (),
172+ Trigger : plan .Trigger .ValueStringPointer (),
173+ Enabled : plan .Enabled .ValueBoolPointer (),
174+ Settings : settings ,
175+ ReverseETLModelId : plan .ModelID .ValueStringPointer (),
176+ ReverseETLSchedule : reverseETLSchedule ,
177+ },
178+ }).Execute ()
179+ if body != nil {
180+ defer body .Body .Close ()
181+ }
182+ if err != nil {
183+ resp .Diagnostics .AddError (
184+ "Unable to update Destination subscription" ,
185+ getError (err , body ),
186+ )
187+
188+ return
189+ }
134190
135- resp . State . SetAttribute ( ctx , path . Root ( "id" ), destinationSubscription . Id )
191+ destinationSubscription := updateOut . Data . Subscription
136192
137193 var state models.DestinationSubscriptionState
138194 err = state .Fill (destinationSubscription )
@@ -203,7 +259,7 @@ func (r *destinationSubscriptionResource) Read(ctx context.Context, req resource
203259}
204260
205261func (r * destinationSubscriptionResource ) Update (ctx context.Context , req resource.UpdateRequest , resp * resource.UpdateResponse ) {
206- var plan models.DestinationSubscriptionState
262+ var plan models.DestinationSubscriptionPlan
207263 diags := req .Plan .Get (ctx , & plan )
208264 resp .Diagnostics .Append (diags ... )
209265 if resp .Diagnostics .HasError () {
@@ -224,12 +280,29 @@ func (r *destinationSubscriptionResource) Update(ctx context.Context, req resour
224280 return
225281 }
226282
283+ if ! plan .ModelID .IsNull () && ! plan .ModelID .IsUnknown () && (plan .ReverseETLSchedule .IsNull () || plan .ReverseETLSchedule .IsUnknown ()) {
284+ resp .Diagnostics .AddError (
285+ "Reverse ETL model ID provided without reverse ETL schedule" ,
286+ "Reverse ETL model ID must be provided with a reverse ETL schedule" ,
287+ )
288+
289+ return
290+ }
291+
292+ reverseETLSchedule , diags := getSchedule (ctx , plan .ReverseETLSchedule )
293+ if diags .HasError () {
294+ resp .Diagnostics .Append (diags ... )
295+ return
296+ }
297+
227298 out , body , err := r .client .DestinationsAPI .UpdateSubscriptionForDestination (r .authContext , state .DestinationID .ValueString (), state .ID .ValueString ()).UpdateSubscriptionForDestinationAlphaInput (api.UpdateSubscriptionForDestinationAlphaInput {
228299 Input : api.DestinationSubscriptionUpdateInput {
229- Name : plan .Name .ValueStringPointer (),
230- Trigger : plan .Trigger .ValueStringPointer (),
231- Enabled : plan .Enabled .ValueBoolPointer (),
232- Settings : settings ,
300+ Name : plan .Name .ValueStringPointer (),
301+ Trigger : plan .Trigger .ValueStringPointer (),
302+ Enabled : plan .Enabled .ValueBoolPointer (),
303+ Settings : settings ,
304+ ReverseETLModelId : plan .ModelID .ValueStringPointer (),
305+ ReverseETLSchedule : reverseETLSchedule ,
233306 },
234307 }).Execute ()
235308 if body != nil {
@@ -320,3 +393,115 @@ func (r *destinationSubscriptionResource) Configure(_ context.Context, req resou
320393 r .client = config .client
321394 r .authContext = config .authContext
322395}
396+
397+ func getSchedule (ctx context.Context , planSchedule basetypes.ObjectValue ) (* api.ReverseEtlScheduleDefinition , diag.Diagnostics ) {
398+ var reverseETLSchedule * api.ReverseEtlScheduleDefinition
399+ var diags diag.Diagnostics
400+ if ! planSchedule .IsNull () && ! planSchedule .IsUnknown () {
401+ reverseETLSchedule = & api.ReverseEtlScheduleDefinition {}
402+
403+ wrappedReverseETLModelScheduleStrategy , err := planSchedule .Attributes ()["strategy" ].ToTerraformValue (ctx )
404+ if err != nil {
405+ diags .AddError (
406+ "Unable to decode reverse ETL schedule strategy" ,
407+ err .Error (),
408+ )
409+
410+ return nil , diags
411+ }
412+
413+ var reverseETLModelScheduleStrategy string
414+ err = wrappedReverseETLModelScheduleStrategy .As (& reverseETLModelScheduleStrategy )
415+ if err != nil {
416+ diags .AddError (
417+ "Unable to decode reverse ETL schedule strategy" ,
418+ err .Error (),
419+ )
420+
421+ return nil , diags
422+ }
423+
424+ reverseETLSchedule .Strategy = reverseETLModelScheduleStrategy
425+
426+ wrappedReverseETLModelScheduleConfig , err := planSchedule .Attributes ()["config" ].ToTerraformValue (ctx )
427+ if err != nil {
428+ diags .AddError (
429+ "Unable to decode reverse ETL schedule config" ,
430+ err .Error (),
431+ )
432+
433+ return nil , diags
434+ }
435+
436+ if ! wrappedReverseETLModelScheduleConfig .IsNull () && wrappedReverseETLModelScheduleConfig .IsKnown () {
437+ if reverseETLSchedule .Strategy == "PERIODIC" {
438+ reverseETLModelScheduleConfig := api.ReverseEtlPeriodicScheduleConfig {}
439+ var config string
440+ err = wrappedReverseETLModelScheduleConfig .As (& config )
441+ if err != nil {
442+ diags .AddError (
443+ "Unable to decode reverse ETL schedule config" ,
444+ err .Error (),
445+ )
446+
447+ return nil , diags
448+ }
449+
450+ err = json .Unmarshal ([]byte (config ), & reverseETLModelScheduleConfig )
451+ if err != nil {
452+ diags .AddError (
453+ "Unable to decode reverse ETL schedule config" ,
454+ err .Error (),
455+ )
456+
457+ return nil , diags
458+ }
459+
460+ reverseETLSchedule .Config = * api .NewNullableConfig (& api.Config {
461+ ReverseEtlPeriodicScheduleConfig : & reverseETLModelScheduleConfig ,
462+ })
463+ } else if reverseETLSchedule .Strategy == "SPECIFIC_DAYS" {
464+ reverseETLModelScheduleConfig := api.ReverseEtlSpecificTimeScheduleConfig {}
465+ var config string
466+ err = wrappedReverseETLModelScheduleConfig .As (& config )
467+ if err != nil {
468+ diags .AddError (
469+ "Unable to decode reverse ETL schedule config" ,
470+ err .Error (),
471+ )
472+
473+ return nil , diags
474+ }
475+
476+ err = json .Unmarshal ([]byte (config ), & reverseETLModelScheduleConfig )
477+ if err != nil {
478+ diags .AddError (
479+ "Unable to decode reverse ETL schedule config" ,
480+ err .Error (),
481+ )
482+
483+ return nil , diags
484+ }
485+
486+ reverseETLSchedule .Config = * api .NewNullableConfig (& api.Config {
487+ ReverseEtlSpecificTimeScheduleConfig : & reverseETLModelScheduleConfig ,
488+ })
489+ } else if reverseETLSchedule .Strategy == "MANUAL" {
490+ diags .AddError (
491+ "Manual reverse ETL schedule strategy does not require a config" ,
492+ "Manual reverse ETL schedule strategy does not require a config" ,
493+ )
494+ reverseETLSchedule .Config = * api .NewNullableConfig (nil )
495+ } else {
496+ diags .AddError (
497+ "Unsupported reverse ETL schedule strategy" ,
498+ fmt .Sprintf ("Strategy %q is not supported" , reverseETLSchedule .Strategy ),
499+ )
500+
501+ return nil , diags
502+ }
503+ }
504+ }
505+
506+ return reverseETLSchedule , diags
507+ }
0 commit comments