From 939d2d1f3148fef163967ab9bda1222af9af9afc Mon Sep 17 00:00:00 2001 From: avallete Date: Mon, 21 Oct 2024 17:55:22 +0200 Subject: [PATCH] fix: add updater logic --- pkg/config/db.go | 36 ++++++++++++++++++++++++++++++------ pkg/config/updater.go | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 64 insertions(+), 7 deletions(-) diff --git a/pkg/config/db.go b/pkg/config/db.go index b9d301861..87f52a2db 100644 --- a/pkg/config/db.go +++ b/pkg/config/db.go @@ -66,26 +66,50 @@ type ( } ) +// Compare two pointers values handling the nil case +func isPointerValueEquals[T comparable](a, b *T) bool { + if a == nil && b == nil { + return true + } + if a == nil || b == nil { + return false + } + return *a == *b +} + +// Compare two db config, if changes requires restart return true, return false otherwise +func requireDbRestart(a *db, b *db) bool { + return !isPointerValueEquals(a.MaxConnections, b.MaxConnections) || + !isPointerValueEquals(a.MaxWorkerProcesses, b.MaxWorkerProcesses) || + !isPointerValueEquals(a.MaxParallelWorkers, b.MaxParallelWorkers) || + !isPointerValueEquals(a.MaxWalSenders, b.MaxWalSenders) || + !isPointerValueEquals(a.MaxReplicationSlots, b.MaxReplicationSlots) || + !isPointerValueEquals(a.SharedBuffers, b.SharedBuffers) +} + func (a *db) ToUpdatePostgresConfigBody() v1API.UpdatePostgresConfigBody { body := v1API.UpdatePostgresConfigBody{} + // Parameters that require restart + body.MaxConnections = cast.UintToIntPtr(a.MaxConnections) + body.MaxWorkerProcesses = cast.UintToIntPtr(a.MaxWorkerProcesses) + body.MaxParallelWorkers = cast.UintToIntPtr(a.MaxParallelWorkers) + body.MaxWalSenders = cast.UintToIntPtr(a.MaxWalSenders) + body.MaxReplicationSlots = cast.UintToIntPtr(a.MaxReplicationSlots) + body.SharedBuffers = a.SharedBuffers + + // Parameters that can be changed without restart body.EffectiveCacheSize = a.EffectiveCacheSize body.LogicalDecodingWorkMem = a.LogicalDecodingWorkMem body.MaintenanceWorkMem = a.MaintenanceWorkMem - body.MaxConnections = cast.UintToIntPtr(a.MaxConnections) body.MaxLocksPerTransaction = cast.UintToIntPtr(a.MaxLocksPerTransaction) body.MaxParallelMaintenanceWorkers = cast.UintToIntPtr(a.MaxParallelMaintenanceWorkers) - body.MaxParallelWorkers = cast.UintToIntPtr(a.MaxParallelWorkers) body.MaxParallelWorkersPerGather = cast.UintToIntPtr(a.MaxParallelWorkersPerGather) - body.MaxReplicationSlots = cast.UintToIntPtr(a.MaxReplicationSlots) body.MaxSlotWalKeepSize = a.MaxSlotWalKeepSize body.MaxStandbyArchiveDelay = a.MaxStandbyArchiveDelay body.MaxStandbyStreamingDelay = a.MaxStandbyStreamingDelay - body.MaxWalSenders = cast.UintToIntPtr(a.MaxWalSenders) body.MaxWalSize = a.MaxWalSize - body.MaxWorkerProcesses = cast.UintToIntPtr(a.MaxWorkerProcesses) body.SessionReplicationRole = (*v1API.UpdatePostgresConfigBodySessionReplicationRole)(a.SessionReplicationRole) - body.SharedBuffers = a.SharedBuffers body.StatementTimeout = a.StatementTimeout body.WalKeepSize = a.WalKeepSize body.WalSenderTimeout = a.WalSenderTimeout diff --git a/pkg/config/updater.go b/pkg/config/updater.go index 467b7bb63..8f69a6310 100644 --- a/pkg/config/updater.go +++ b/pkg/config/updater.go @@ -21,7 +21,9 @@ func (u *ConfigUpdater) UpdateRemoteConfig(ctx context.Context, remote baseConfi if err := u.UpdateApiConfig(ctx, remote.ProjectId, remote.Api); err != nil { return err } - // TODO: implement other service configs, ie. auth + if err := u.UpdateDbConfig(ctx, remote.ProjectId, remote.Db); err != nil { + return err + } return nil } @@ -40,6 +42,7 @@ func (u *ConfigUpdater) UpdateApiConfig(ctx context.Context, projectRef string, return nil } fmt.Fprintln(os.Stderr, "Updating API service with config:", string(apiDiff)) + if resp, err := u.client.V1UpdatePostgrestServiceConfigWithResponse(ctx, projectRef, c.ToUpdatePostgrestConfigBody()); err != nil { return errors.Errorf("failed to update API config: %w", err) } else if resp.JSON200 == nil { @@ -47,3 +50,33 @@ func (u *ConfigUpdater) UpdateApiConfig(ctx context.Context, projectRef string, } return nil } + +func (u *ConfigUpdater) UpdateDbConfig(ctx context.Context, projectRef string, c db) error { + dbConfig, err := u.client.V1GetPostgresConfigWithResponse(ctx, projectRef) + if err != nil { + return errors.Errorf("failed to read DB config: %w", err) + } else if dbConfig.JSON200 == nil { + return errors.Errorf("unexpected status %d: %s", dbConfig.StatusCode(), string(dbConfig.Body)) + } + dbDiff, err := c.DiffWithRemote(*dbConfig.JSON200) + if err != nil { + return err + } else if len(dbDiff) == 0 { + fmt.Fprintln(os.Stderr, "Remote DB config is up to date.") + return nil + } + fmt.Fprintln(os.Stderr, "Updating DB service with config:", string(dbDiff)) + remoteConfig := c.fromRemoteApiConfig(*dbConfig.JSON200) + restartRequired := requireDbRestart(&c, &remoteConfig) + if restartRequired { + fmt.Fprintln(os.Stderr, "DB service updates will require database restart...") + } + updateBody := c.ToUpdatePostgresConfigBody() + updateBody.RestartDatabase = &restartRequired + if resp, err := u.client.V1UpdatePostgresConfigWithResponse(ctx, projectRef, updateBody); err != nil { + return errors.Errorf("failed to update DB config: %w", err) + } else if resp.JSON200 == nil { + return errors.Errorf("unexpected status %d: %s", resp.StatusCode(), string(resp.Body)) + } + return nil +}