From f0b8e2bc222fdff507fb529941286673fca0e2dd Mon Sep 17 00:00:00 2001 From: Laura Martin Date: Tue, 13 Aug 2024 15:58:00 +0100 Subject: [PATCH] Add server-side batching --- go.mod | 2 +- go.sum | 2 + internal/provider/models.go | 3 + internal/provider/resource_ably_namespace.go | 66 +++++++++++++++++++ .../provider/resource_ably_namespace_test.go | 66 ++++++++++++++++++- 5 files changed, 137 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 6f2b1e1..cb59b0f 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/ably/terraform-provider-ably go 1.19 require ( - github.com/ably/ably-control-go v0.3.0 + github.com/ably/ably-control-go v0.4.0 github.com/hashicorp/terraform-plugin-docs v0.13.0 github.com/hashicorp/terraform-plugin-framework v0.16.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.21.0 diff --git a/go.sum b/go.sum index 5cf859f..3a068c6 100644 --- a/go.sum +++ b/go.sum @@ -14,6 +14,8 @@ github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 h1:YoJbenK9C6 github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= github.com/ably/ably-control-go v0.3.0 h1:m5Y2SHE69Mwg8iDASZxqmlHFSwpejN4s2TgZi3EIVMQ= github.com/ably/ably-control-go v0.3.0/go.mod h1:TP7gWAy+ga++gX6OZ0DtjwH8oVKKdiaIGQvZvxDKNdk= +github.com/ably/ably-control-go v0.4.0 h1:JouYcHKT2TvvAGPpEPQJcFo5p9k1KfLUr/k9bfy+tYI= +github.com/ably/ably-control-go v0.4.0/go.mod h1:TP7gWAy+ga++gX6OZ0DtjwH8oVKKdiaIGQvZvxDKNdk= github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk= github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= diff --git a/internal/provider/models.go b/internal/provider/models.go index df3d720..df19ed3 100644 --- a/internal/provider/models.go +++ b/internal/provider/models.go @@ -28,6 +28,9 @@ type AblyNamespace struct { PushEnabled types.Bool `tfsdk:"push_enabled"` TlsOnly types.Bool `tfsdk:"tls_only"` ExposeTimeserial types.Bool `tfsdk:"expose_timeserial"` + BatchingEnabled types.Bool `tfsdk:"batching_enabled"` + BatchingPolicy types.String `tfsdk:"batching_policy"` + BatchingInterval types.Int64 `tfsdk:"batching_interval"` } // Ably Key diff --git a/internal/provider/resource_ably_namespace.go b/internal/provider/resource_ably_namespace.go index efc2513..309640d 100644 --- a/internal/provider/resource_ably_namespace.go +++ b/internal/provider/resource_ably_namespace.go @@ -88,6 +88,33 @@ func (r resourceNamespace) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diag DefaultAttribute(types.BoolValue(false)), }, }, + "batching_enabled": { + Type: types.BoolType, + Optional: true, + Computed: true, + Description: "If true, channels within this namespace will start batching inbound messages instead of sending them out immediately to subscribers as per the configured policy.", + PlanModifiers: []tfsdk.AttributePlanModifier{ + DefaultAttribute(types.BoolValue(false)), + }, + }, + "batching_policy": { + Type: types.StringType, + Optional: true, + Computed: true, + Description: "When configured, sets the policy for message batching.", + PlanModifiers: []tfsdk.AttributePlanModifier{ + DefaultAttribute(types.StringNull()), + }, + }, + "batching_interval": { + Type: types.Int64Type, + Optional: true, + Computed: true, + Description: "When configured, sets the maximium batching interval in the channel.", + PlanModifiers: []tfsdk.AttributePlanModifier{ + DefaultAttribute(types.Int64Null()), + }, + }, }, MarkdownDescription: "The ably_namespace resource allows you to manage namespaces for channel rules in Ably. Read more in the Ably documentation: https://ably.com/docs/general/channel-rules-namespaces.", }, nil @@ -123,6 +150,12 @@ func (r resourceNamespace) Create(ctx context.Context, req tfsdk_resource.Create ExposeTimeserial: plan.ExposeTimeserial.ValueBool(), } + if plan.BatchingEnabled.ValueBool() { + namespace_values.BatchingEnabled = true + namespace_values.BatchingPolicy = plan.BatchingPolicy.ValueString() + namespace_values.BatchingInterval = ably_control_go.BatchingInterval(int(plan.BatchingInterval.ValueInt64())) + } + // Creates a new Ably namespace by invoking the CreateNamespace function from the Client Library ably_namespace, err := r.p.client.CreateNamespace(plan.AppID.ValueString(), &namespace_values) if err != nil { @@ -133,6 +166,12 @@ func (r resourceNamespace) Create(ctx context.Context, req tfsdk_resource.Create return } + // Handle the pointer gracefully + batchingInterval := types.Int64Null() + if ably_namespace.BatchingInterval != nil { + batchingInterval = types.Int64Value(int64(*ably_namespace.BatchingInterval)) + } + // Maps response body to resource schema attributes. resp_apps := AblyNamespace{ AppID: types.StringValue(plan.AppID.ValueString()), @@ -143,6 +182,9 @@ func (r resourceNamespace) Create(ctx context.Context, req tfsdk_resource.Create PushEnabled: types.BoolValue(ably_namespace.PushEnabled), TlsOnly: types.BoolValue(ably_namespace.TlsOnly), ExposeTimeserial: types.BoolValue(namespace_values.ExposeTimeserial), + BatchingEnabled: types.BoolValue(ably_namespace.BatchingEnabled), + BatchingPolicy: types.StringValue(ably_namespace.BatchingPolicy), + BatchingInterval: batchingInterval, } // Sets state for the new Ably App. @@ -191,6 +233,12 @@ func (r resourceNamespace) Read(ctx context.Context, req tfsdk_resource.ReadRequ // Loops through namespaces and if id matches, sets state. for _, v := range namespaces { if v.ID == namespace_id { + // Handle the pointer gracefully + batchingInterval := types.Int64Null() + if v.BatchingInterval != nil { + batchingInterval = types.Int64Value(int64(*v.BatchingInterval)) + } + resp_namespaces := AblyNamespace{ AppID: types.StringValue(app_id), ID: types.StringValue(namespace_id), @@ -200,6 +248,9 @@ func (r resourceNamespace) Read(ctx context.Context, req tfsdk_resource.ReadRequ PushEnabled: types.BoolValue(v.PushEnabled), TlsOnly: types.BoolValue(v.TlsOnly), ExposeTimeserial: types.BoolValue(v.ExposeTimeserial), + BatchingEnabled: types.BoolValue(v.BatchingEnabled), + BatchingPolicy: types.StringValue(v.BatchingPolicy), + BatchingInterval: batchingInterval, } // Sets state to namespace values. diags = resp.State.Set(ctx, &resp_namespaces) @@ -243,6 +294,12 @@ func (r resourceNamespace) Update(ctx context.Context, req tfsdk_resource.Update ExposeTimeserial: plan.ExposeTimeserial.ValueBool(), } + if plan.BatchingEnabled.ValueBool() { + namespace_values.BatchingEnabled = true + namespace_values.BatchingPolicy = plan.BatchingPolicy.ValueString() + namespace_values.BatchingInterval = ably_control_go.BatchingInterval(int(plan.BatchingInterval.ValueInt64())) + } + // Updates an Ably Namespace. The function invokes the Client Library UpdateNamespace method. ably_namespace, err := r.p.client.UpdateNamespace(app_id, &namespace_values) if err != nil { @@ -253,6 +310,12 @@ func (r resourceNamespace) Update(ctx context.Context, req tfsdk_resource.Update return } + // Handle the pointer gracefully + batchingInterval := types.Int64Null() + if ably_namespace.BatchingInterval != nil { + batchingInterval = types.Int64Value(int64(*ably_namespace.BatchingInterval)) + } + resp_namespaces := AblyNamespace{ AppID: types.StringValue(app_id), ID: types.StringValue(ably_namespace.ID), @@ -262,6 +325,9 @@ func (r resourceNamespace) Update(ctx context.Context, req tfsdk_resource.Update PushEnabled: types.BoolValue(ably_namespace.PushEnabled), TlsOnly: types.BoolValue(ably_namespace.TlsOnly), ExposeTimeserial: types.BoolValue(ably_namespace.ExposeTimeserial), + BatchingEnabled: types.BoolValue(ably_namespace.BatchingEnabled), + BatchingPolicy: types.StringValue(ably_namespace.BatchingPolicy), + BatchingInterval: batchingInterval, } // Sets state to new namespace. diff --git a/internal/provider/resource_ably_namespace_test.go b/internal/provider/resource_ably_namespace_test.go index 89c7402..8ac5f12 100644 --- a/internal/provider/resource_ably_namespace_test.go +++ b/internal/provider/resource_ably_namespace_test.go @@ -81,6 +81,33 @@ func TestAccAblyNamespace(t *testing.T) { resource.TestCheckResourceAttr("ably_namespace.namespace0", "expose_timeserial", "false"), ), }, + { + Config: testAccAblyNamespaceBatchingConfig(app_name, ably_control_go.Namespace{ + ID: namespace_name + "batching", + Authenticated: false, + Persisted: false, + PersistLast: false, + PushEnabled: false, + TlsOnly: false, + ExposeTimeserial: false, + BatchingEnabled: true, + BatchingPolicy: "some-policy", + BatchingInterval: ably_control_go.BatchingInterval(100), + }), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ably_app.app0", "name", app_name), + resource.TestCheckResourceAttr("ably_namespace.namespace0", "id", namespace_name+"new"), + resource.TestCheckResourceAttr("ably_namespace.namespace0", "authenticated", "false"), + resource.TestCheckResourceAttr("ably_namespace.namespace0", "persisted", "false"), + resource.TestCheckResourceAttr("ably_namespace.namespace0", "persist_last", "false"), + resource.TestCheckResourceAttr("ably_namespace.namespace0", "push_enabled", "false"), + resource.TestCheckResourceAttr("ably_namespace.namespace0", "tls_only", "false"), + resource.TestCheckResourceAttr("ably_namespace.namespace0", "expose_timeserial", "false"), + resource.TestCheckResourceAttr("ably_namespace.namespace0", "batching_enabled", "true"), + resource.TestCheckResourceAttr("ably_namespace.namespace0", "batching_policy", "some-policy"), + resource.TestCheckResourceAttr("ably_namespace.namespace0", "batching_interval", "100"), + ), + }, // Delete testing automatically occurs in TestCase }, }) @@ -97,7 +124,7 @@ terraform { } } } - + # You can provide your Ably Token & URL inline or use environment variables ABLY_ACCOUNT_TOKEN & ABLY_URL provider "ably" {} @@ -120,3 +147,40 @@ resource "ably_namespace" "namespace0" { `, appName, namespace.ID, namespace.Authenticated, namespace.Persisted, namespace.PersistLast, namespace.PushEnabled, namespace.TlsOnly, namespace.ExposeTimeserial) } + +func testAccAblyNamespaceBatchingConfig(appName string, namespace ably_control_go.Namespace) string { + return fmt.Sprintf(` +terraform { + required_providers { + ably = { + source = "github.com/ably/ably" + version = "0.4.3" + } + } +} + +# You can provide your Ably Token & URL inline or use environment variables ABLY_ACCOUNT_TOKEN & ABLY_URL +provider "ably" {} + +resource "ably_app" "app0" { + name = %[1]q + status = "enabled" + tls_only = true +} + +resource "ably_namespace" "namespace0" { + app_id = ably_app.app0.id + id = %[2]q + authenticated = %[3]t + persisted = %[4]t + persist_last = %[5]t + push_enabled = %[6]t + tls_only = %[7]t + expose_timeserial = %[8]t + batching_enabled = %[9]t + batching_policy = %[10]s + batching_interval = %[11]d +} + +`, appName, namespace.ID, namespace.Authenticated, namespace.Persisted, namespace.PersistLast, namespace.PushEnabled, namespace.TlsOnly, namespace.ExposeTimeserial, namespace.BatchingEnabled, namespace.BatchingPolicy, *namespace.BatchingInterval) +}