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 17, 2024
1 parent 84cda97 commit 4b145c3
Show file tree
Hide file tree
Showing 10 changed files with 366 additions and 7 deletions.
14 changes: 12 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,16 @@ 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:]')
# Add error checking for supported architectures
ARCH_NATIVE := $(shell uname -m)
ARCH_MAPPED := $(shell echo "$(ARCH_NATIVE)" | sed -e 's/x86_64/amd64/' -e 's/aarch64/arm64/' -e 's/armv7l/arm/')
ifeq ($(ARCH_MAPPED),$(ARCH_NATIVE))
$(error Unsupported architecture: $(ARCH_NATIVE))
endif
ARCH ?= $(ARCH_MAPPED)
OS_ARCH=${OS}_${ARCH}

default: install

Expand All @@ -13,11 +21,13 @@ build:

release:
GOOS=darwin GOARCH=amd64 go build -ldflags="-X main.VERSION=${VERSION}" -o ./bin/${BINARY}_${VERSION}_darwin_amd64
GOOS=darwin GOARCH=arm64 go build -ldflags="-X main.VERSION=${VERSION}" -o ./bin/${BINARY}_${VERSION}_darwin_arm64
GOOS=freebsd GOARCH=386 go build -ldflags="-X main.VERSION=${VERSION}" -o ./bin/${BINARY}_${VERSION}_freebsd_386
GOOS=freebsd GOARCH=amd64 go build -ldflags="-X main.VERSION=${VERSION}" -o ./bin/${BINARY}_${VERSION}_freebsd_amd64
GOOS=freebsd GOARCH=arm go build -ldflags="-X main.VERSION=${VERSION}" -o ./bin/${BINARY}_${VERSION}_freebsd_arm
GOOS=linux GOARCH=386 go build -ldflags="-X main.VERSION=${VERSION}" -o ./bin/${BINARY}_${VERSION}_linux_386
GOOS=linux GOARCH=amd64 go build -ldflags="-X main.VERSION=${VERSION}" -o ./bin/${BINARY}_${VERSION}_linux_amd64
GOOS=linux GOARCH=arm64 go build -ldflags="-X main.VERSION=${VERSION}" -o ./bin/${BINARY}_${VERSION}_linux_arm64
GOOS=linux GOARCH=arm go build -ldflags="-X main.VERSION=${VERSION}" -o ./bin/${BINARY}_${VERSION}_linux_arm
GOOS=openbsd GOARCH=386 go build -ldflags="-X main.VERSION=${VERSION}" -o ./bin/${BINARY}_${VERSION}_openbsd_386
GOOS=openbsd GOARCH=amd64 go build -ldflags="-X main.VERSION=${VERSION}" -o ./bin/${BINARY}_${VERSION}_openbsd_amd64
Expand Down
54 changes: 54 additions & 0 deletions docs/resources/ingress_rule_postgres_outbox.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "ably_ingress_rule_postgres_outbox Resource - terraform-provider-ably"
subcategory: ""
description: |-
The ably_ingress_rule_postgres_outbox resource Use the Postgres database connector to distribute changes from your Postgres database to end users at scale. It enables you to distribute records using the outbox pattern to large numbers of subscribing clients, in realtime, as the changes occur.
---

# ably_ingress_rule_postgres_outbox (Resource)

The `ably_ingress_rule_postgres_outbox` resource Use the Postgres database connector to distribute changes from your Postgres database to end users at scale. It enables you to distribute records using the outbox pattern to large numbers of subscribing clients, in realtime, as the changes occur.



<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `app_id` (String) The Ably application ID.
- `target` (Attributes) object (rule_source) (see [below for nested schema](#nestedatt--target))

### Optional

- `status` (String) The status of the rule. Rules can be enabled or disabled.

### Read-Only

- `id` (String) The rule ID.

<a id="nestedatt--target"></a>
### Nested Schema for `target`

Required:

- `nodes_table_name` (String) Name for the nodes table.
- `nodes_table_schema` (String) Schema for the nodes table in your database to allow for operation as a cluster to provide fault tolerance.
- `outbox_table_name` (String) Name for the outbox table.
- `outbox_table_schema` (String) Schema for the outbox table in your database which allows for the reliable publication of an ordered sequence of change event messages over Ably.
- `primary_site` (String) The primary data center in which to run the integration rule.
- `ssl_mode` (String) + ssl_mode (String) Determines the level of protection provided by the SSL connection. Options are:
- prefer: Attempt SSL but allow non-SSL.
- require: Always use SSL but don't verify certificates.
- verify-ca: Verify server certificate is signed by a trusted CA.
- verify-full: Verify server certificate and hostname.

Default: prefer.
- `url` (String) The URL for your Postgres database, for example postgres://user:password@example.com:5432/your-database-name. The associated user must have the correct privileges

Optional:

- `ssl_root_cert` (String) Optional. Specifies the SSL certificate authority (CA) certificates. Required if SSL mode is verify-ca or verify-full.


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://${var.postgres_user}:${var.postgres_password}@${var.postgres_host}:5432/${var.postgres_db}"
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
38 changes: 38 additions & 0 deletions examples/playground/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
variable "mongodb_user" {
description = "MongoDB username"
sensitive = true
default = "test"
}

variable "mongodb_password" {
description = "MongoDB password"
sensitive = true
default = "test"
}

variable "mongodb_host" {
description = "MongoDB host"
default = "test"
}

variable "postgres_user" {
description = "PostgreSQL username"
sensitive = true
default = "test"
}

variable "postgres_password" {
description = "PostgreSQL password"
sensitive = true
default = "test"
}

variable "postgres_host" {
description = "PostgreSQL host"
default = "test"
}

variable "postgres_db" {
description = "PostgreSQL database name"
default = "test"
}
27 changes: 24 additions & 3 deletions 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 Expand Up @@ -174,8 +195,8 @@ func ReadIngressRule[T any](r IngressRule, ctx context.Context, req tfsdk_resour
return
}
resp.Diagnostics.AddError(
fmt.Sprintf("Error deleting Resource %s", r.Name()),
fmt.Sprintf("Could not delete resource %s, unexpected error: %s", r.Name(), err.Error()),
fmt.Sprintf("Error reading Resource %s", r.Name()),
fmt.Sprintf("Could not read resource %s, unexpected error: %s", r.Name(), err.Error()),
)
return
}
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
105 changes: 105 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,105 @@
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: "The URL for your Postgres database, for example postgres://user:[email protected]:5432/your-database-name. The associated user must have the correct privileges",
},
"outbox_table_schema": {
Type: types.StringType,
Required: true,
Description: "Schema for the outbox table in your database which allows for the reliable publication of an ordered sequence of change event messages over Ably.",
},
"outbox_table_name": {
Type: types.StringType,
Required: true,
Description: "Name for the outbox table.",
},
"nodes_table_schema": {
Type: types.StringType,
Required: true,
Description: "Schema for the nodes table in your database to allow for operation as a cluster to provide fault tolerance.",
},
"nodes_table_name": {
Type: types.StringType,
Required: true,
Description: "Name for the nodes table.",
},
"ssl_mode": {
Type: types.StringType,
Required: true,
Description: `+ ssl_mode (String) Determines the level of protection provided by the SSL connection. Options are:
- prefer: Attempt SSL but allow non-SSL.
- require: Always use SSL but don't verify certificates.
- verify-ca: Verify server certificate is signed by a trusted CA.
- verify-full: Verify server certificate and hostname.
Default: prefer.`,
},
"ssl_root_cert": {
Type: types.StringType,
Optional: true,
Description: "Optional. Specifies the SSL certificate authority (CA) certificates. Required if SSL mode is verify-ca or verify-full.",
},
"primary_site": {
Type: types.StringType,
Required: true,
Description: " The primary data center in which to run the integration rule.",
},
},
"The `ably_ingress_rule_postgres_outbox` resource Use the Postgres database connector to distribute changes from your Postgres database to end users at scale. It enables you to distribute records using the outbox pattern to large numbers of subscribing clients, in realtime, as the changes occur."), 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")
}
Loading

0 comments on commit 4b145c3

Please sign in to comment.