From e2677d93a4d774c02f177f5737d3a6f16bbcc5f6 Mon Sep 17 00:00:00 2001 From: Adarsh Shah Date: Mon, 30 Oct 2023 23:29:41 -0400 Subject: [PATCH] adds connection_pooler to tembo_instance resource --- docs/resources/instance.md | 31 ++++++ examples/resource-creation/main.tf | 18 +++- internal/provider/instance_resource.go | 126 +++++++++++++++++++++---- 3 files changed, 154 insertions(+), 21 deletions(-) diff --git a/docs/resources/instance.md b/docs/resources/instance.md index 12e165a..2b8dcb0 100644 --- a/docs/resources/instance.md +++ b/docs/resources/instance.md @@ -78,6 +78,7 @@ output "instance" { ### Optional +- `connection_pooler` (Attributes) (see [below for nested schema](#nestedatt--connection_pooler)) - `extensions` (Attributes List) Extensions to install in the instance (see [below for nested schema](#nestedatt--extensions)) - `extra_domains_rw` (List of String) Custom domain. Read more [here](https://tembo.io/docs/tembo-cloud/custom-domains/) - `ip_allow_list` (List of String) Allowed IP list @@ -91,6 +92,36 @@ output "instance" { - `last_updated` (String) Last updated date time in UTC - `state` (String) Instance state. Values: Submitted, Up, Configuring, Error, Restarting, Starting, Stopping, Stopped, Deleting, Deleted + +### Nested Schema for `connection_pooler` + +Required: + +- `enabled` (Boolean) + +Optional: + +- `pooler` (Attributes) (see [below for nested schema](#nestedatt--connection_pooler--pooler)) + + +### Nested Schema for `connection_pooler.pooler` + +Required: + +- `parameters` (Attributes List) Parameters (see [below for nested schema](#nestedatt--connection_pooler--pooler--parameters)) +- `pool_mode` (String) + + +### Nested Schema for `connection_pooler.pooler.parameters` + +Required: + +- `name` (String) Parameter name +- `value` (String) Parameter value + + + + ### Nested Schema for `extensions` diff --git a/examples/resource-creation/main.tf b/examples/resource-creation/main.tf index c0d4fbe..30fabab 100644 --- a/examples/resource-creation/main.tf +++ b/examples/resource-creation/main.tf @@ -1,5 +1,5 @@ resource "tembo_instance" "test_db" { - instance_name = "tfprovider-de2345" + instance_name = "tfprovider-4" org_id = "org_2UJ2WPYFsE42Cos6mlmIuwIIJ4V" cpu = "1" stack_type = "Standard" @@ -63,6 +63,22 @@ resource "tembo_instance" "test_db" { } ] }] + connection_pooler = { + enabled = true, + pooler = { + pool_mode = "transaction", + parameters = [ + { + name = "max_client_conn" + value = "50" + }, + { + name = "default_pool_size" + value = "5000" + } + ] + } + } } data "tembo_instance_secrets" "test" { diff --git a/internal/provider/instance_resource.go b/internal/provider/instance_resource.go index b2e79d9..5c7e8e1 100644 --- a/internal/provider/instance_resource.go +++ b/internal/provider/instance_resource.go @@ -43,25 +43,35 @@ const ( // temboInstanceResourceModel maps the resource schema data. type temboInstanceResourceModel struct { - InstanceID types.String `tfsdk:"instance_id"` - InstanceName types.String `tfsdk:"instance_name"` - OrgId types.String `tfsdk:"org_id"` - CPU types.String `tfsdk:"cpu"` - StackType types.String `tfsdk:"stack_type"` - Environment types.String `tfsdk:"environment"` - Replicas types.Int64 `tfsdk:"replicas"` - Memory types.String `tfsdk:"memory"` - Storage types.String `tfsdk:"storage"` - LastUpdated types.String `tfsdk:"last_updated"` - State types.String `tfsdk:"state"` - ExtraDomainsRw []types.String `tfsdk:"extra_domains_rw"` - PostgresConfigs []PostGresConfig `tfsdk:"postgres_configs"` - TrunkInstalls []TrunkInstall `tfsdk:"trunk_installs"` - Extensions []Extension `tfsdk:"extensions"` - IpAllowList []types.String `tfsdk:"ip_allow_list"` + InstanceID types.String `tfsdk:"instance_id"` + InstanceName types.String `tfsdk:"instance_name"` + OrgId types.String `tfsdk:"org_id"` + CPU types.String `tfsdk:"cpu"` + StackType types.String `tfsdk:"stack_type"` + Environment types.String `tfsdk:"environment"` + Replicas types.Int64 `tfsdk:"replicas"` + Memory types.String `tfsdk:"memory"` + Storage types.String `tfsdk:"storage"` + LastUpdated types.String `tfsdk:"last_updated"` + State types.String `tfsdk:"state"` + ExtraDomainsRw []types.String `tfsdk:"extra_domains_rw"` + PostgresConfigs []KeyValue `tfsdk:"postgres_configs"` + TrunkInstalls []TrunkInstall `tfsdk:"trunk_installs"` + Extensions []Extension `tfsdk:"extensions"` + IpAllowList []types.String `tfsdk:"ip_allow_list"` + ConnectionPooler ConnectionPooler `tfsdk:"connection_pooler"` } -type PostGresConfig struct { +type ConnectionPooler struct { + Enabled types.Bool `tfsdk:"enabled"` + Pooler PgBouncer `tfsdk:"pooler"` +} +type PgBouncer struct { + Parameters []KeyValue `tfsdk:"parameters"` + PoolMode types.String `tfsdk:"pool_mode"` +} + +type KeyValue struct { Name types.String `tfsdk:"name"` Value types.String `tfsdk:"value"` } @@ -269,6 +279,38 @@ func (r *temboInstanceResource) Schema(_ context.Context, _ resource.SchemaReque Optional: true, ElementType: types.StringType, }, + "connection_pooler": schema.SingleNestedAttribute{ + Attributes: map[string]schema.Attribute{ + "enabled": schema.BoolAttribute{ + Required: true, + }, + "pooler": schema.SingleNestedAttribute{ + Optional: true, + Attributes: map[string]schema.Attribute{ + "pool_mode": schema.StringAttribute{ + Required: true, + }, + "parameters": schema.ListNestedAttribute{ + MarkdownDescription: "Parameters", + Required: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "name": schema.StringAttribute{ + MarkdownDescription: "Parameter name", + Required: true, + }, + "value": schema.StringAttribute{ + MarkdownDescription: "Parameter value", + Required: true, + }, + }, + }, + }, + }, + }, + }, + Optional: true, + }, }, } } @@ -306,6 +348,8 @@ func (r *temboInstanceResource) Create(ctx context.Context, req resource.CreateR createInstance.SetIpAllowList(getStringArray(plan.IpAllowList)) + createInstance.SetConnectionPooler(getConnectionPooler(plan.ConnectionPooler)) + // TODO: Figure out a better way to set this so it doesn't have to be be called in each method. ctx = context.WithValue(ctx, temboclient.ContextAccessToken, r.temboInstanceConfig.accessToken) @@ -404,6 +448,7 @@ func (r *temboInstanceResource) Update(ctx context.Context, req resource.UpdateR updateInstance.SetTrunkInstalls(getTemboTrunkInstalls(plan.TrunkInstalls)) updateInstance.SetExtensions(getTemboExtensions(plan.Extensions)) updateInstance.SetIpAllowList(getStringArray(plan.IpAllowList)) + updateInstance.SetConnectionPooler(getConnectionPooler(plan.ConnectionPooler)) ctx = context.WithValue(ctx, temboclient.ContextAccessToken, r.temboInstanceConfig.accessToken) @@ -521,9 +566,9 @@ func setTemboInstanceResourceModel(instanceResourceModel *temboInstanceResourceM } if len(instance.PostgresConfigs) > 0 { - var localPGConfigs []PostGresConfig + var localPGConfigs []KeyValue for _, pgConfig := range instance.PostgresConfigs { - localPGConfigs = append(localPGConfigs, PostGresConfig{Name: types.StringValue(pgConfig.Name), Value: types.StringValue(pgConfig.Value)}) + localPGConfigs = append(localPGConfigs, KeyValue{Name: types.StringValue(pgConfig.Name), Value: types.StringValue(pgConfig.Value)}) } instanceResourceModel.PostgresConfigs = localPGConfigs } @@ -562,6 +607,15 @@ func setTemboInstanceResourceModel(instanceResourceModel *temboInstanceResourceM instanceResourceModel.IpAllowList = localIpAllowList } + //if instance.HasConnectionPooler() { + var localConnectionPooler ConnectionPooler + cp := instance.ConnectionPooler.Get() + localConnectionPooler.Enabled = types.BoolValue(*cp.Enabled) + localConnectionPooler.Pooler.PoolMode = types.StringValue(string(*cp.Pooler.PoolMode.Ptr())) + localConnectionPooler.Pooler.Parameters = getParameterKV(cp.Pooler.Parameters) + instanceResourceModel.ConnectionPooler = localConnectionPooler + //} + } func getStringArray(inputArray []basetypes.StringValue) []string { @@ -574,7 +628,7 @@ func getStringArray(inputArray []basetypes.StringValue) []string { return localStringArray } -func getPgConfig(postgresConfigs []PostGresConfig) []temboclient.PgConfig { +func getPgConfig(postgresConfigs []KeyValue) []temboclient.PgConfig { var localPGConfigs []temboclient.PgConfig if len(postgresConfigs) > 0 { for _, pgConfig := range postgresConfigs { @@ -603,6 +657,38 @@ func getTemboTrunkInstall(trunkInstall TrunkInstall) temboclient.TrunkInstall { return localTrunkInstall } +func getConnectionPooler(connectionPooler ConnectionPooler) temboclient.ConnectionPooler { + localConnectionPooler := temboclient.ConnectionPooler{ + Enabled: connectionPooler.Enabled.ValueBoolPointer(), + } + + localConnectionPooler.Pooler = &temboclient.PgBouncer{ + Parameters: getParameterMap(connectionPooler.Pooler.Parameters), + PoolMode: (*temboclient.PoolerPgbouncerPoolMode)(connectionPooler.Pooler.PoolMode.ValueStringPointer()), + } + + return localConnectionPooler +} + +func getParameterMap(parameters []KeyValue) map[string]string { + localParameters := make(map[string]string) + + for _, kv := range parameters { + localParameters[kv.Name.ValueString()] = kv.Value.ValueString() + } + return localParameters +} + +func getParameterKV(parameters map[string]string) []KeyValue { + var localParams []KeyValue + + for name, value := range parameters { + localParams = append(localParams, KeyValue{Name: types.StringValue(name), Value: types.StringValue(value)}) + } + + return localParams +} + func getTemboExtensions(extensions []Extension) []temboclient.Extension { var tcExtensions []temboclient.Extension