From ce888ad95abd926ac420fd242e06e7fe991496b4 Mon Sep 17 00:00:00 2001 From: Dmitrii Creed Date: Mon, 23 Mar 2026 16:56:59 +0400 Subject: [PATCH 1/4] Add backup, HA, and SSL configuration support for Cloud SQL New optional fields for gcp-cloudsql-postgres resource: - backupEnabled, backupStartTime, pointInTimeRecoveryEnabled - transactionLogRetentionDays, retainedBackups - availabilityType (ZONAL/REGIONAL) - requireSsl All fields are optional and nil-safe. When not set, Cloud SQL defaults apply (no change to existing behavior). Example server.yaml: postgres: type: gcp-cloudsql-postgres config: backupEnabled: true backupStartTime: '02:00' pointInTimeRecoveryEnabled: true transactionLogRetentionDays: 7 retainedBackups: 30 availabilityType: REGIONAL requireSsl: true --- pkg/clouds/gcloud/postgres.go | 10 +++++++++ pkg/clouds/pulumi/gcp/postgres.go | 37 +++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/pkg/clouds/gcloud/postgres.go b/pkg/clouds/gcloud/postgres.go index a9faecc6..dff613d2 100644 --- a/pkg/clouds/gcloud/postgres.go +++ b/pkg/clouds/gcloud/postgres.go @@ -15,6 +15,16 @@ type PostgresGcpCloudsqlConfig struct { QueryInsightsEnabled *bool `json:"queryInsightsEnabled" yaml:"queryInsightsEnabled"` QueryStringLength *int `json:"queryStringLength" yaml:"queryStringLength"` UsersProvisionRuntime *ProvisionRuntimeConfig `json:"usersProvisionRuntime" yaml:"usersProvisionRuntime"` + // Backup configuration + BackupEnabled *bool `json:"backupEnabled,omitempty" yaml:"backupEnabled,omitempty"` + BackupStartTime *string `json:"backupStartTime,omitempty" yaml:"backupStartTime,omitempty"` + PointInTimeRecoveryEnabled *bool `json:"pointInTimeRecoveryEnabled,omitempty" yaml:"pointInTimeRecoveryEnabled,omitempty"` + TransactionLogRetentionDays *int `json:"transactionLogRetentionDays,omitempty" yaml:"transactionLogRetentionDays,omitempty"` + RetainedBackups *int `json:"retainedBackups,omitempty" yaml:"retainedBackups,omitempty"` + // High availability + AvailabilityType *string `json:"availabilityType,omitempty" yaml:"availabilityType,omitempty"` // ZONAL or REGIONAL + // SSL + RequireSsl *bool `json:"requireSsl,omitempty" yaml:"requireSsl,omitempty"` // Resource adoption fields Adopt bool `json:"adopt,omitempty" yaml:"adopt,omitempty"` InstanceName string `json:"instanceName,omitempty" yaml:"instanceName,omitempty"` diff --git a/pkg/clouds/pulumi/gcp/postgres.go b/pkg/clouds/pulumi/gcp/postgres.go index 150e30fb..1f409edf 100644 --- a/pkg/clouds/pulumi/gcp/postgres.go +++ b/pkg/clouds/pulumi/gcp/postgres.go @@ -72,6 +72,11 @@ func Postgres(ctx *sdk.Context, stack api.Stack, input api.ResourceInput, params lo.If(pgCfg.QueryStringLength != nil, lo.FromPtr(pgCfg.QueryStringLength)).Else(2048), ), }, + BackupConfiguration: backupConfiguration(pgCfg), + AvailabilityType: sdk.StringPtrFromPtr( + lo.If(pgCfg.AvailabilityType != nil, pgCfg.AvailabilityType).Else(nil), + ), + IpConfiguration: ipConfiguration(pgCfg), }, DeletionProtection: sdk.Bool(pgCfg.DeletionProtection != nil && *pgCfg.DeletionProtection), }, sdk.Provider(params.Provider)) @@ -82,6 +87,38 @@ func Postgres(ctx *sdk.Context, stack api.Stack, input api.ResourceInput, params return &api.ResourceOutput{Ref: pgInstance}, nil } +func backupConfiguration(pgCfg *gcloud.PostgresGcpCloudsqlConfig) *sql.DatabaseInstanceSettingsBackupConfigurationArgs { + if pgCfg.BackupEnabled == nil || !*pgCfg.BackupEnabled { + return nil + } + args := &sql.DatabaseInstanceSettingsBackupConfigurationArgs{ + Enabled: sdk.Bool(true), + PointInTimeRecoveryEnabled: sdk.Bool(pgCfg.PointInTimeRecoveryEnabled != nil && *pgCfg.PointInTimeRecoveryEnabled), + } + if pgCfg.BackupStartTime != nil { + args.StartTime = sdk.StringPtr(*pgCfg.BackupStartTime) + } + if pgCfg.TransactionLogRetentionDays != nil { + args.TransactionLogRetentionDays = sdk.Int(*pgCfg.TransactionLogRetentionDays) + } + if pgCfg.RetainedBackups != nil { + args.BackupRetentionSettings = &sql.DatabaseInstanceSettingsBackupConfigurationBackupRetentionSettingsArgs{ + RetainedBackups: sdk.Int(*pgCfg.RetainedBackups), + RetentionUnit: sdk.String("COUNT"), + } + } + return args +} + +func ipConfiguration(pgCfg *gcloud.PostgresGcpCloudsqlConfig) *sql.DatabaseInstanceSettingsIpConfigurationArgs { + if pgCfg.RequireSsl == nil || !*pgCfg.RequireSsl { + return nil + } + return &sql.DatabaseInstanceSettingsIpConfigurationArgs{ + RequireSsl: sdk.Bool(true), + } +} + func toPostgresRootPasswordExport(resName string) string { return fmt.Sprintf("%s-root-password", resName) } From 68514c604c7d7c74dca228da48372f1556b1fbf0 Mon Sep 17 00:00:00 2001 From: Dmitrii Creed Date: Mon, 23 Mar 2026 17:08:02 +0400 Subject: [PATCH 2/4] Fix review issues: validate AvailabilityType, fix SSL field name, preserve IP config - Validate AvailabilityType is ZONAL or REGIONAL (error early) - Use SslMode (Pulumi GCP SDK v8) instead of deprecated RequireSsl - Preserve Ipv4Enabled when setting SSL to avoid wiping IP config - Simplify AvailabilityType expression --- pkg/clouds/pulumi/gcp/postgres.go | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/pkg/clouds/pulumi/gcp/postgres.go b/pkg/clouds/pulumi/gcp/postgres.go index 1f409edf..2a8c51c1 100644 --- a/pkg/clouds/pulumi/gcp/postgres.go +++ b/pkg/clouds/pulumi/gcp/postgres.go @@ -25,6 +25,12 @@ func Postgres(ctx *sdk.Context, stack api.Stack, input api.ResourceInput, params return nil, errors.Errorf("failed to convert postgresql config for %q", input.Descriptor.Type) } + if pgCfg.AvailabilityType != nil { + if *pgCfg.AvailabilityType != "ZONAL" && *pgCfg.AvailabilityType != "REGIONAL" { + return nil, errors.Errorf("availabilityType must be ZONAL or REGIONAL, got %q", *pgCfg.AvailabilityType) + } + } + // Handle resource adoption - exit early if adopting if pgCfg.Adopt { return AdoptPostgres(ctx, stack, input, params) @@ -73,9 +79,7 @@ func Postgres(ctx *sdk.Context, stack api.Stack, input api.ResourceInput, params ), }, BackupConfiguration: backupConfiguration(pgCfg), - AvailabilityType: sdk.StringPtrFromPtr( - lo.If(pgCfg.AvailabilityType != nil, pgCfg.AvailabilityType).Else(nil), - ), + AvailabilityType: sdk.StringPtrFromPtr(pgCfg.AvailabilityType), IpConfiguration: ipConfiguration(pgCfg), }, DeletionProtection: sdk.Bool(pgCfg.DeletionProtection != nil && *pgCfg.DeletionProtection), @@ -110,12 +114,23 @@ func backupConfiguration(pgCfg *gcloud.PostgresGcpCloudsqlConfig) *sql.DatabaseI return args } +// ipConfiguration returns IP settings only when requireSsl is explicitly set. +// When nil, returns nil so Pulumi leaves existing IP configuration unchanged. +// Preserves Ipv4Enabled=true to avoid wiping existing authorized networks. +// ipConfiguration returns IP settings only when requireSsl is explicitly set. +// When nil, returns nil so Pulumi leaves existing IP configuration unchanged. +// Uses SslMode (Pulumi GCP SDK v8) instead of deprecated RequireSsl. func ipConfiguration(pgCfg *gcloud.PostgresGcpCloudsqlConfig) *sql.DatabaseInstanceSettingsIpConfigurationArgs { - if pgCfg.RequireSsl == nil || !*pgCfg.RequireSsl { + if pgCfg.RequireSsl == nil { return nil } + sslMode := "ALLOW_UNENCRYPTED_AND_ENCRYPTED" + if *pgCfg.RequireSsl { + sslMode = "ENCRYPTED_ONLY" + } return &sql.DatabaseInstanceSettingsIpConfigurationArgs{ - RequireSsl: sdk.Bool(true), + Ipv4Enabled: sdk.Bool(true), + SslMode: sdk.String(sslMode), } } From 03bd26d607d532b4fbc6292a8e7416a0b9563869 Mon Sep 17 00:00:00 2001 From: Dmitrii Creed Date: Mon, 23 Mar 2026 17:11:38 +0400 Subject: [PATCH 3/4] Remove duplicate comment on ipConfiguration --- pkg/clouds/pulumi/gcp/postgres.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pkg/clouds/pulumi/gcp/postgres.go b/pkg/clouds/pulumi/gcp/postgres.go index 2a8c51c1..0e11e6d2 100644 --- a/pkg/clouds/pulumi/gcp/postgres.go +++ b/pkg/clouds/pulumi/gcp/postgres.go @@ -114,12 +114,10 @@ func backupConfiguration(pgCfg *gcloud.PostgresGcpCloudsqlConfig) *sql.DatabaseI return args } -// ipConfiguration returns IP settings only when requireSsl is explicitly set. -// When nil, returns nil so Pulumi leaves existing IP configuration unchanged. -// Preserves Ipv4Enabled=true to avoid wiping existing authorized networks. // ipConfiguration returns IP settings only when requireSsl is explicitly set. // When nil, returns nil so Pulumi leaves existing IP configuration unchanged. // Uses SslMode (Pulumi GCP SDK v8) instead of deprecated RequireSsl. +// Preserves Ipv4Enabled=true to avoid wiping existing authorized networks. func ipConfiguration(pgCfg *gcloud.PostgresGcpCloudsqlConfig) *sql.DatabaseInstanceSettingsIpConfigurationArgs { if pgCfg.RequireSsl == nil { return nil From f29456a41dab89c14596c808eff8647fbf6010c0 Mon Sep 17 00:00:00 2001 From: Dmitrii Creed Date: Mon, 23 Mar 2026 17:42:34 +0400 Subject: [PATCH 4/4] Fix gofumpt alignment for AvailabilityType and IpConfiguration --- pkg/clouds/pulumi/gcp/postgres.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/clouds/pulumi/gcp/postgres.go b/pkg/clouds/pulumi/gcp/postgres.go index 0e11e6d2..82caa880 100644 --- a/pkg/clouds/pulumi/gcp/postgres.go +++ b/pkg/clouds/pulumi/gcp/postgres.go @@ -79,8 +79,8 @@ func Postgres(ctx *sdk.Context, stack api.Stack, input api.ResourceInput, params ), }, BackupConfiguration: backupConfiguration(pgCfg), - AvailabilityType: sdk.StringPtrFromPtr(pgCfg.AvailabilityType), - IpConfiguration: ipConfiguration(pgCfg), + AvailabilityType: sdk.StringPtrFromPtr(pgCfg.AvailabilityType), + IpConfiguration: ipConfiguration(pgCfg), }, DeletionProtection: sdk.Bool(pgCfg.DeletionProtection != nil && *pgCfg.DeletionProtection), }, sdk.Provider(params.Provider))