Skip to content

Commit

Permalink
[INF-5307] - Add the Postgres Outbox Ably Ingress Rule
Browse files Browse the repository at this point in the history
This adds the new Ably Ingress rule for Postgres Outbox. Documentation on this rule can be found at https://ably.com/docs/livesync/postgres
  • Loading branch information
graham-russell committed Dec 16, 2024
1 parent 1341ff7 commit 8be5958
Show file tree
Hide file tree
Showing 9 changed files with 277 additions and 5 deletions.
6 changes: 4 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ HOSTNAME=github.com
NAMESPACE=ably
NAME=ably
BINARY=terraform-provider-${NAME}
VERSION=0.4.3
OS_ARCH=darwin_amd64
VERSION=0.8.0
OS ?= $(shell uname -s | tr '[:upper:]' '[:lower:]')
ARCH ?= $(shell uname -m | sed 's/x86_64/amd64/' | sed 's/aarch64/arm64/')
OS_ARCH=${OS}_${ARCH}

default: install

Expand Down
19 changes: 19 additions & 0 deletions examples/playground/ingress_rule_mongodb.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
resource "ably_ingress_rule_mongodb" "rule0" {
app_id = ably_app.app0.id
status = "enabled"
target = {
url = "mongodb://coco:nut@coco.io:27017"
database = "coconut"
collection = "coconut"
pipeline = jsonencode([
{
"$set" = {
"_ablyChannel" = "myChannel"
}
}
])
full_document = "off"
full_document_before_change = "off"
primary_site = "us-east-1-A"
}
}
14 changes: 14 additions & 0 deletions examples/playground/ingress_rule_postgres_outbox.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
resource "ably_ingress_rule_postgres_outbox" "rule0" {
app_id = ably_app.app0.id
status = "enabled"
target = {
url = "postgres://user:password@example.com:5432/your-database-name"
outbox_table_schema = "public"
outbox_table_name = "outbox"
nodes_table_schema = "public"
nodes_table_name = "nodes"
ssl_mode = "prefer"
ssl_root_cert = "-----BEGIN CERTIFICATE----- MIIFiTCCA3GgAwIBAgIUYO1Lomxzj7VRawWwEFiQht9OLpUwDQYJKoZIhvcNAQEL BQAwTDELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1pY2hpZ2FuMQ8wDQYDVQQHDAZX ...snip... TOfReTlUQzgpXRW5h3n2LVXbXQhPGcVitb88Cm2R8cxQwgB1VncM8yvmKhREo2tz 7Y+sUx6eIl4dlNl9kVrH1TD3EwwtGsjUNlFSZhg= -----END CERTIFICATE-----"
primary_site = "us-east-1-A"
}
}
4 changes: 2 additions & 2 deletions examples/playground/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ terraform {

required_providers {
ably = {
source = "ably/ably"
version = ">=0.4.2"
source = "local/ably/ably"
version = "0.8.0"
}
}
}
Expand Down
23 changes: 22 additions & 1 deletion internal/provider/ingress_rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,17 @@ func GetPlanIngressRule(plan AblyIngressRule) ably_control_go.NewIngressRule {
FullDocumentBeforeChange: t.FullDocumentBeforeChange,
PrimarySite: t.PrimarySite,
}
case *AblyIngressRuleTargetPostgresOutbox:
target = &ably_control_go.IngressPostgresOutboxTarget{
Url: t.Url,
OutboxTableSchema: t.OutboxTableSchema,
OutboxTableName: t.OutboxTableName,
NodesTableSchema: t.NodesTableSchema,
NodesTableName: t.NodesTableName,
SslMode: t.SslMode,
SslRootCert: t.SslRootCert,
PrimarySite: t.PrimarySite,
}
}

rule_values := ably_control_go.NewIngressRule{
Expand All @@ -44,7 +55,6 @@ func GetIngressRuleResponse(ably_ingress_rule *ably_control_go.IngressRule, plan

switch v := ably_ingress_rule.Target.(type) {
case *ably_control_go.IngressMongoTarget:

resp_target = &AblyIngressRuleTargetMongo{
Url: v.Url,
Database: v.Database,
Expand All @@ -54,6 +64,17 @@ func GetIngressRuleResponse(ably_ingress_rule *ably_control_go.IngressRule, plan
FullDocumentBeforeChange: v.FullDocumentBeforeChange,
PrimarySite: v.PrimarySite,
}
case *ably_control_go.IngressPostgresOutboxTarget:
resp_target = &AblyIngressRuleTargetPostgresOutbox{
Url: v.Url,
OutboxTableSchema: v.OutboxTableSchema,
OutboxTableName: v.OutboxTableName,
NodesTableSchema: v.NodesTableSchema,
NodesTableName: v.NodesTableName,
SslMode: v.SslMode,
SslRootCert: v.SslRootCert,
PrimarySite: v.PrimarySite,
}
}

resp_rule := AblyIngressRule{
Expand Down
11 changes: 11 additions & 0 deletions internal/provider/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,17 @@ type AblyIngressRuleTargetMongo struct {
PrimarySite string `tfsdk:"primary_site"`
}

type AblyIngressRuleTargetPostgresOutbox struct {
Url string `tfsdk:"url"`
OutboxTableSchema string `tfsdk:"outbox_table_schema"`
OutboxTableName string `tfsdk:"outbox_table_name"`
NodesTableSchema string `tfsdk:"nodes_table_schema"`
NodesTableName string `tfsdk:"nodes_table_name"`
SslMode string `tfsdk:"ssl_mode"`
SslRootCert string `tfsdk:"ssl_root_cert"`
PrimarySite string `tfsdk:"primary_site"`
}

// Ably Rule
type AblyRuleSource struct {
ChannelFilter types.String `tfsdk:"channel_filter"`
Expand Down
1 change: 1 addition & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ func (p *provider) Resources(context.Context) []func() tfsdk_resource.Resource {
func() tfsdk_resource.Resource { return resourceRuleAmqp{p} },
func() tfsdk_resource.Resource { return resourceRuleAmqpExternal{p} },
func() tfsdk_resource.Resource { return resourceIngressRuleMongo{p} },
func() tfsdk_resource.Resource { return resourceIngressRulePostgresOutbox{p} },
}

}
Expand Down
99 changes: 99 additions & 0 deletions internal/provider/resource_ably_ingress_rule_postgres_outbox.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package ably_control

import (
"context"

"github.com/hashicorp/terraform-plugin-framework/diag"
tfsdk_resource "github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
)

type resourceIngressRulePostgresOutbox struct {
p *provider
}

// Get Rule Resource schema
func (r resourceIngressRulePostgresOutbox) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diagnostics) {
return GetIngressRuleSchema(
map[string]tfsdk.Attribute{
"url": {
Type: types.StringType,
Required: true,
Description: "",
},
"outbox_table_schema": {
Type: types.StringType,
Required: true,
Description: "",
},
"outbox_table_name": {
Type: types.StringType,
Required: true,
Description: "",
},
"nodes_table_schema": {
Type: types.StringType,
Required: true,
Description: "",
},
"nodes_table_name": {
Type: types.StringType,
Required: true,
Description: "",
},
"ssl_mode": {
Type: types.StringType,
Required: true,
Description: "",
},
"ssl_root_cert": {
Type: types.StringType,
Required: true,
Description: "",
},
"primary_site": {
Type: types.StringType,
Required: true,
Description: "",
},
},
"The `ably_ingress_rule_postgres_outbox` resource allows you to create and manage an Ably Ingress rule for PostgreSQL. Read more at "), nil
}

func (r resourceIngressRulePostgresOutbox) Metadata(ctx context.Context, req tfsdk_resource.MetadataRequest, resp *tfsdk_resource.MetadataResponse) {
resp.TypeName = "ably_ingress_rule_postgres_outbox"
}

func (r *resourceIngressRulePostgresOutbox) Provider() *provider {
return r.p
}

func (r *resourceIngressRulePostgresOutbox) Name() string {
return "PostgresOutbox"
}

// Create a new resource
func (r resourceIngressRulePostgresOutbox) Create(ctx context.Context, req tfsdk_resource.CreateRequest, resp *tfsdk_resource.CreateResponse) {
CreateIngressRule[AblyIngressRuleTargetPostgresOutbox](&r, ctx, req, resp)
}

// Read resource
func (r resourceIngressRulePostgresOutbox) Read(ctx context.Context, req tfsdk_resource.ReadRequest, resp *tfsdk_resource.ReadResponse) {
ReadIngressRule[AblyIngressRuleTargetPostgresOutbox](&r, ctx, req, resp)
}

// Update resource
func (r resourceIngressRulePostgresOutbox) Update(ctx context.Context, req tfsdk_resource.UpdateRequest, resp *tfsdk_resource.UpdateResponse) {
UpdateIngressRule[AblyIngressRuleTargetPostgresOutbox](&r, ctx, req, resp)
}

// Delete resource
func (r resourceIngressRulePostgresOutbox) Delete(ctx context.Context, req tfsdk_resource.DeleteRequest, resp *tfsdk_resource.DeleteResponse) {
DeleteIngressRule[AblyIngressRuleTargetPostgresOutbox](&r, ctx, req, resp)
}

// Import resource
func (r resourceIngressRulePostgresOutbox) ImportState(ctx context.Context, req tfsdk_resource.ImportStateRequest, resp *tfsdk_resource.ImportStateResponse) {
ImportResource(ctx, req, resp, "app_id", "id")
}
105 changes: 105 additions & 0 deletions internal/provider/resource_ably_ingress_rule_postgres_outbox_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package ably_control

import (
"fmt"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"testing"
)

func TestAccAblyIngressRulePostgresOutbox(t *testing.T) {
app_name := acctest.RandStringFromCharSet(15, acctest.CharSetAlphaNum)
// update_app_name := "acc-test-" + app_name
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
// Create and Read testing of ably_app.app0
{
Config: testAccAblyIngressRulePostgresOutboxConfig(
app_name,
"enabled",
),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("ably_app.app0", "name", app_name),
resource.TestCheckResourceAttr("ably_ingress_rule_postgres_outbox.rule0", "status", "enabled"),
resource.TestCheckResourceAttr("ably_ingress_rule_postgres_outbox.rule0", "target.url", "postgres://user:password@example.com:5432/your-database-name"),
resource.TestCheckResourceAttr("ably_ingress_rule_postgres_outbox.rule0", "target.outbox_table_schema", "public"),
resource.TestCheckResourceAttr("ably_ingress_rule_postgres_outbox.rule0", "target.outbox_table_name", "outbox"),
resource.TestCheckResourceAttr("ably_ingress_rule_postgres_outbox.rule0", "target.nodes_table_schema", "public"),
resource.TestCheckResourceAttr("ably_ingress_rule_postgres_outbox.rule0", "target.nodes_table_name", "nodes"),
resource.TestCheckResourceAttr("ably_ingress_rule_postgres_outbox.rule0", "target.ssl_mode", "prefer"),
resource.TestCheckResourceAttr("ably_ingress_rule_postgres_outbox.rule0", "target.ssl_root_cert", "-----BEGIN CERTIFICATE----- MIIFiTCCA3GgAwIBAgIUYO1Lomxzj7VRawWwEFiQht9OLpUwDQYJKoZIhvcNAQEL BQAwTDELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1pY2hpZ2FuMQ8wDQYDVQQHDAZX ...snip... TOfReTlUQzgpXRW5h3n2LVXbXQhPGcVitb88Cm2R8cxQwgB1VncM8yvmKhREo2tz 7Y+sUx6eIl4dlNl9kVrH1TD3EwwtGsjUNlFSZhg= -----END CERTIFICATE-----"),
resource.TestCheckResourceAttr("ably_ingress_rule_postgres_outbox.rule0", "target.primary_site", "us-east-1-A"),
),
},
// Update and Read testing of ably_app.app0
// {
// Config: testAccAblyIngressRulePostgresOutboxConfig(
// update_app_name,
// "enabled",
// "^my-channel.*",
// "channel.message",
// "single",
// update_headers_block,
// "false",
// "msgpack",
// ),
// Check: resource.ComposeAggregateTestCheckFunc(
// resource.TestCheckResourceAttr("ably_app.app0", "name", app_name),
// resource.TestCheckResourceAttr("ably_ingress_rule_postgres_outbox.rule0", "status", "enabled"),
// resource.TestCheckResourceAttr("ably_ingress_rule_postgres_outbox.rule0", "target.url", "postgres://user:password@example.com:5432/your-database-name"),
// resource.TestCheckResourceAttr("ably_ingress_rule_postgres_outbox.rule0", "target.outbox_table_schema", "public"),
// resource.TestCheckResourceAttr("ably_ingress_rule_postgres_outbox.rule0", "target.outbox_table_name", "outbox"),
// resource.TestCheckResourceAttr("ably_ingress_rule_postgres_outbox.rule0", "target.nodes_table_schema", "public"),
// resource.TestCheckResourceAttr("ably_ingress_rule_postgres_outbox.rule0", "target.nodes_table_name", "nodes"),
// resource.TestCheckResourceAttr("ably_ingress_rule_postgres_outbox.rule0", "target.ssl_mode", "prefer"),
// resource.TestCheckResourceAttr("ably_ingress_rule_postgres_outbox.rule0", "target.ssl_root_cert", "-----BEGIN CERTIFICATE----- MIIFiTCCA3GgAwIBAgIUYO1Lomxzj7VRawWwEFiQht9OLpUwDQYJKoZIhvcNAQEL BQAwTDELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1pY2hpZ2FuMQ8wDQYDVQQHDAZX ...snip... TOfReTlUQzgpXRW5h3n2LVXbXQhPGcVitb88Cm2R8cxQwgB1VncM8yvmKhREo2tz 7Y+sUx6eIl4dlNl9kVrH1TD3EwwtGsjUNlFSZhg= -----END CERTIFICATE-----"),
// resource.TestCheckResourceAttr("ably_ingress_rule_postgres_outbox.rule0", "target.primary_site", "us-east-1-A"),
// ),
// },
// Delete testing automatically occurs in TestCase
},
})
}

// Function with inline HCL to provision an ably_app resource
func testAccAblyIngressRulePostgresOutboxConfig(
appName string,
ruleStatus string,
) string {
return fmt.Sprintf(`
terraform {
required_providers {
ably = {
source = "github.com/ably/ably"
}
}
}
# 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_ingress_rule_postgres_outbox" "rule0" {
app_id = ably_app.app0.id
status = %[2]q
target = {
url = "postgres://user:password@example.com:5432/your-database-name"
outbox_table_schema = "public"
outbox_table_name = "outbox"
nodes_table_schema = "public"
nodes_table_name = "nodes"
ssl_mode = "prefer"
ssl_root_cert = "-----BEGIN CERTIFICATE----- MIIFiTCCA3GgAwIBAgIUYO1Lomxzj7VRawWwEFiQht9OLpUwDQYJKoZIhvcNAQEL BQAwTDELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1pY2hpZ2FuMQ8wDQYDVQQHDAZX ...snip... TOfReTlUQzgpXRW5h3n2LVXbXQhPGcVitb88Cm2R8cxQwgB1VncM8yvmKhREo2tz 7Y+sUx6eIl4dlNl9kVrH1TD3EwwtGsjUNlFSZhg= -----END CERTIFICATE-----"
primary_site = "us-east-1-A"
}
}
`, appName, ruleStatus)
}

0 comments on commit 8be5958

Please sign in to comment.