190 lines
8.2 KiB
Go
190 lines
8.2 KiB
Go
package config
|
|
|
|
import (
|
|
"bytes"
|
|
|
|
"github.com/go-errors/errors"
|
|
v1API "github.com/supabase/cli/pkg/api"
|
|
"github.com/supabase/cli/pkg/cast"
|
|
"github.com/supabase/cli/pkg/diff"
|
|
)
|
|
|
|
type PoolMode string
|
|
|
|
const (
|
|
TransactionMode PoolMode = "transaction"
|
|
SessionMode PoolMode = "session"
|
|
)
|
|
|
|
func (m *PoolMode) UnmarshalText(text []byte) error {
|
|
allowed := []PoolMode{TransactionMode, SessionMode}
|
|
if *m = PoolMode(text); !sliceContains(allowed, *m) {
|
|
return errors.Errorf("must be one of %v", allowed)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type SessionReplicationRole string
|
|
|
|
const (
|
|
SessionReplicationRoleOrigin SessionReplicationRole = "origin"
|
|
SessionReplicationRoleReplica SessionReplicationRole = "replica"
|
|
SessionReplicationRoleLocal SessionReplicationRole = "local"
|
|
)
|
|
|
|
func (r *SessionReplicationRole) UnmarshalText(text []byte) error {
|
|
allowed := []SessionReplicationRole{SessionReplicationRoleOrigin, SessionReplicationRoleReplica, SessionReplicationRoleLocal}
|
|
if *r = SessionReplicationRole(text); !sliceContains(allowed, *r) {
|
|
return errors.Errorf("must be one of %v", allowed)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type (
|
|
settings struct {
|
|
EffectiveCacheSize *string `toml:"effective_cache_size"`
|
|
LogicalDecodingWorkMem *string `toml:"logical_decoding_work_mem"`
|
|
MaintenanceWorkMem *string `toml:"maintenance_work_mem"`
|
|
MaxConnections *uint `toml:"max_connections"`
|
|
MaxLocksPerTransaction *uint `toml:"max_locks_per_transaction"`
|
|
MaxParallelMaintenanceWorkers *uint `toml:"max_parallel_maintenance_workers"`
|
|
MaxParallelWorkers *uint `toml:"max_parallel_workers"`
|
|
MaxParallelWorkersPerGather *uint `toml:"max_parallel_workers_per_gather"`
|
|
MaxReplicationSlots *uint `toml:"max_replication_slots"`
|
|
MaxSlotWalKeepSize *string `toml:"max_slot_wal_keep_size"`
|
|
MaxStandbyArchiveDelay *string `toml:"max_standby_archive_delay"`
|
|
MaxStandbyStreamingDelay *string `toml:"max_standby_streaming_delay"`
|
|
MaxWalSize *string `toml:"max_wal_size"`
|
|
MaxWalSenders *uint `toml:"max_wal_senders"`
|
|
MaxWorkerProcesses *uint `toml:"max_worker_processes"`
|
|
SessionReplicationRole *SessionReplicationRole `toml:"session_replication_role"`
|
|
SharedBuffers *string `toml:"shared_buffers"`
|
|
StatementTimeout *string `toml:"statement_timeout"`
|
|
TrackActivityQuerySize *string `toml:"track_activity_query_size"`
|
|
TrackCommitTimestamp *bool `toml:"track_commit_timestamp"`
|
|
WalKeepSize *string `toml:"wal_keep_size"`
|
|
WalSenderTimeout *string `toml:"wal_sender_timeout"`
|
|
WorkMem *string `toml:"work_mem"`
|
|
}
|
|
|
|
db struct {
|
|
Image string `toml:"-"`
|
|
Port uint16 `toml:"port"`
|
|
ShadowPort uint16 `toml:"shadow_port"`
|
|
MajorVersion uint `toml:"major_version"`
|
|
Password string `toml:"-"`
|
|
RootKey string `toml:"-" mapstructure:"root_key"`
|
|
Pooler pooler `toml:"pooler"`
|
|
Migrations migrations `toml:"migrations"`
|
|
Seed seed `toml:"seed"`
|
|
Settings settings `toml:"settings"`
|
|
Vault map[string]Secret `toml:"vault"`
|
|
}
|
|
|
|
migrations struct {
|
|
SchemaPaths Glob `toml:"schema_paths"`
|
|
}
|
|
|
|
seed struct {
|
|
Enabled bool `toml:"enabled"`
|
|
SqlPaths Glob `toml:"sql_paths"`
|
|
}
|
|
|
|
pooler struct {
|
|
Enabled bool `toml:"enabled"`
|
|
Image string `toml:"-"`
|
|
Port uint16 `toml:"port"`
|
|
PoolMode PoolMode `toml:"pool_mode"`
|
|
DefaultPoolSize uint `toml:"default_pool_size"`
|
|
MaxClientConn uint `toml:"max_client_conn"`
|
|
ConnectionString string `toml:"-"`
|
|
TenantId string `toml:"-"`
|
|
EncryptionKey string `toml:"-"`
|
|
SecretKeyBase string `toml:"-"`
|
|
}
|
|
)
|
|
|
|
func (a *settings) 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.MaxLocksPerTransaction = cast.UintToIntPtr(a.MaxLocksPerTransaction)
|
|
body.MaxParallelMaintenanceWorkers = cast.UintToIntPtr(a.MaxParallelMaintenanceWorkers)
|
|
body.MaxParallelWorkersPerGather = cast.UintToIntPtr(a.MaxParallelWorkersPerGather)
|
|
body.MaxSlotWalKeepSize = a.MaxSlotWalKeepSize
|
|
body.MaxStandbyArchiveDelay = a.MaxStandbyArchiveDelay
|
|
body.MaxStandbyStreamingDelay = a.MaxStandbyStreamingDelay
|
|
body.MaxWalSize = a.MaxWalSize
|
|
body.SessionReplicationRole = (*v1API.UpdatePostgresConfigBodySessionReplicationRole)(a.SessionReplicationRole)
|
|
body.StatementTimeout = a.StatementTimeout
|
|
body.TrackActivityQuerySize = a.TrackActivityQuerySize
|
|
body.TrackCommitTimestamp = a.TrackCommitTimestamp
|
|
body.WalKeepSize = a.WalKeepSize
|
|
body.WalSenderTimeout = a.WalSenderTimeout
|
|
body.WorkMem = a.WorkMem
|
|
return body
|
|
}
|
|
|
|
func (a *settings) FromRemotePostgresConfig(remoteConfig v1API.PostgresConfigResponse) {
|
|
a.EffectiveCacheSize = remoteConfig.EffectiveCacheSize
|
|
a.LogicalDecodingWorkMem = remoteConfig.LogicalDecodingWorkMem
|
|
a.MaintenanceWorkMem = remoteConfig.MaintenanceWorkMem
|
|
a.MaxConnections = cast.IntToUintPtr(remoteConfig.MaxConnections)
|
|
a.MaxLocksPerTransaction = cast.IntToUintPtr(remoteConfig.MaxLocksPerTransaction)
|
|
a.MaxParallelMaintenanceWorkers = cast.IntToUintPtr(remoteConfig.MaxParallelMaintenanceWorkers)
|
|
a.MaxParallelWorkers = cast.IntToUintPtr(remoteConfig.MaxParallelWorkers)
|
|
a.MaxParallelWorkersPerGather = cast.IntToUintPtr(remoteConfig.MaxParallelWorkersPerGather)
|
|
a.MaxReplicationSlots = cast.IntToUintPtr(remoteConfig.MaxReplicationSlots)
|
|
a.MaxSlotWalKeepSize = remoteConfig.MaxSlotWalKeepSize
|
|
a.MaxStandbyArchiveDelay = remoteConfig.MaxStandbyArchiveDelay
|
|
a.MaxStandbyStreamingDelay = remoteConfig.MaxStandbyStreamingDelay
|
|
a.MaxWalSenders = cast.IntToUintPtr(remoteConfig.MaxWalSenders)
|
|
a.MaxWalSize = remoteConfig.MaxWalSize
|
|
a.MaxWorkerProcesses = cast.IntToUintPtr(remoteConfig.MaxWorkerProcesses)
|
|
a.SessionReplicationRole = (*SessionReplicationRole)(remoteConfig.SessionReplicationRole)
|
|
a.SharedBuffers = remoteConfig.SharedBuffers
|
|
a.StatementTimeout = remoteConfig.StatementTimeout
|
|
a.TrackActivityQuerySize = remoteConfig.TrackActivityQuerySize
|
|
a.TrackCommitTimestamp = remoteConfig.TrackCommitTimestamp
|
|
a.WalKeepSize = remoteConfig.WalKeepSize
|
|
a.WalSenderTimeout = remoteConfig.WalSenderTimeout
|
|
a.WorkMem = remoteConfig.WorkMem
|
|
}
|
|
|
|
const pgConfHeader = "\n# supabase [db.settings] configuration\n"
|
|
|
|
// create a valid string to append to /etc/postgresql/postgresql.conf
|
|
func (a *settings) ToPostgresConfig() string {
|
|
// Assuming postgres settings is always a flat struct, we can serialise
|
|
// using toml, then replace double quotes with single.
|
|
data, _ := ToTomlBytes(*a)
|
|
body := bytes.ReplaceAll(data, []byte{'"'}, []byte{'\''})
|
|
return pgConfHeader + string(body)
|
|
}
|
|
|
|
func (a *settings) DiffWithRemote(remoteConfig v1API.PostgresConfigResponse) ([]byte, error) {
|
|
copy := *a
|
|
// Convert the config values into easily comparable remoteConfig values
|
|
currentValue, err := ToTomlBytes(copy)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
copy.FromRemotePostgresConfig(remoteConfig)
|
|
remoteCompare, err := ToTomlBytes(copy)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return diff.Diff("remote[db.settings]", remoteCompare, "local[db.settings]", currentValue), nil
|
|
}
|