Skip to content

Commit cfbc8c7

Browse files
authored
[!] use native Postgres connection parameters and ENVVARs (#695)
Drop all custom connection parameters and move to the native Postgres handling, e.g. PGHOST, PGPORT, etc. Allow user to specify a whole connection string with `--constr` or as unnamed parameter.
1 parent 9cc36e7 commit cfbc8c7

File tree

4 files changed

+21
-59
lines changed

4 files changed

+21
-59
lines changed

internal/config/cmdparser.go

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,6 @@ import (
77
flags "github.com/jessevdk/go-flags"
88
)
99

10-
// ConnectionOpts specifies the database connection options
11-
type ConnectionOpts struct {
12-
Host string `short:"h" long:"host" description:"PostgreSQL host" default:"localhost" env:"PGTT_PGHOST"`
13-
Port int `short:"p" long:"port" description:"PostgreSQL port" default:"5432" env:"PGTT_PGPORT"`
14-
DBName string `short:"d" long:"dbname" description:"PostgreSQL database name" default:"timetable" env:"PGTT_PGDATABASE"`
15-
User string `short:"u" long:"user" description:"PostgreSQL user" default:"scheduler" env:"PGTT_PGUSER"`
16-
Password string `long:"password" description:"PostgreSQL user password" env:"PGTT_PGPASSWORD"`
17-
SSLMode string `long:"sslmode" default:"disable" description:"Connection SSL mode" env:"PGTT_PGSSLMODE" choice:"disable" choice:"require"`
18-
PgURL string `long:"pgurl" description:"PostgreSQL connection URL" env:"PGTT_URL"`
19-
Timeout int `long:"timeout" description:"PostgreSQL connection timeout" env:"PGTT_TIMEOUT" default:"90"`
20-
}
21-
2210
// LoggingOpts specifies the logging configuration
2311
type LoggingOpts struct {
2412
LogLevel string `long:"log-level" mapstructure:"log-level" description:"Verbosity level for stdout and log file" choice:"debug" choice:"info" choice:"error" default:"info"`
@@ -54,16 +42,16 @@ type RestAPIOpts struct {
5442

5543
// CmdOptions holds command line options passed
5644
type CmdOptions struct {
57-
ClientName string `short:"c" long:"clientname" description:"Unique name for application instance" env:"PGTT_CLIENTNAME"`
58-
Config string `long:"config" description:"YAML configuration file"`
59-
Connection ConnectionOpts `group:"Connection" mapstructure:"Connection"`
60-
Logging LoggingOpts `group:"Logging" mapstructure:"Logging"`
61-
Start StartOpts `group:"Start" mapstructure:"Start"`
62-
Resource ResourceOpts `group:"Resource" mapstructure:"Resource"`
63-
RESTApi RestAPIOpts `group:"REST" mapstructure:"REST"`
64-
NoProgramTasks bool `long:"no-program-tasks" mapstructure:"no-program-tasks" description:"Disable executing of PROGRAM tasks" env:"PGTT_NOPROGRAMTASKS"`
65-
NoHelpMessage bool `long:"no-help" mapstructure:"no-help" hidden:"system use"`
66-
Version bool `short:"v" long:"version" mapstructure:"version" description:"Output detailed version information" env:"PGTT_VERSION"`
45+
ClientName string `short:"c" long:"clientname" description:"Unique name for application instance" env:"PGTT_CLIENTNAME"`
46+
Config string `long:"config" description:"YAML configuration file"`
47+
ConnStr string `long:"connstr" description:"Connection string" env:"PGTT_CONNSTR"`
48+
Logging LoggingOpts `group:"Logging" mapstructure:"Logging"`
49+
Start StartOpts `group:"Start" mapstructure:"Start"`
50+
Resource ResourceOpts `group:"Resource" mapstructure:"Resource"`
51+
RESTApi RestAPIOpts `group:"REST" mapstructure:"REST"`
52+
NoProgramTasks bool `long:"no-program-tasks" mapstructure:"no-program-tasks" description:"Disable executing of PROGRAM tasks" env:"PGTT_NOPROGRAMTASKS"`
53+
NoHelpMessage bool `long:"no-help" mapstructure:"no-help" hidden:"system use"`
54+
Version bool `short:"v" long:"version" mapstructure:"version" description:"Output detailed version information" env:"PGTT_VERSION"`
6755
}
6856

6957
// Verbose returns true if the debug log is enabled
@@ -102,8 +90,8 @@ func Parse(writer io.Writer) (*flags.Parser, error) {
10290
}
10391
}
10492
//non-option arguments
105-
if len(nonOptionArgs) > 0 && cmdOpts.Connection.PgURL == "" {
106-
cmdOpts.Connection.PgURL = nonOptionArgs[0]
93+
if len(nonOptionArgs) > 0 && cmdOpts.ConnStr == "" {
94+
cmdOpts.ConnStr = nonOptionArgs[0]
10795
}
10896
return parser, nil
10997
}

internal/pgengine/bootstrap.go

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package pgengine
33
import (
44
"context"
55
"errors"
6-
"fmt"
76
"math/rand"
87
"os"
98
"strings"
@@ -80,9 +79,7 @@ var sqlNames = []string{"Schema Init", "Cron Functions", "Tables and Views", "JS
8079
// New opens connection and creates schema
8180
func New(ctx context.Context, cmdOpts config.CmdOptions, logger log.LoggerHookerIface) (*PgEngine, error) {
8281
var (
83-
err error
84-
connctx = ctx
85-
conncancel context.CancelFunc
82+
err error
8683
)
8784
pge := &PgEngine{
8885
l: logger,
@@ -91,15 +88,10 @@ func New(ctx context.Context, cmdOpts config.CmdOptions, logger log.LoggerHooker
9188
chainSignalChan: make(chan ChainSignal, 64),
9289
}
9390
pge.l.WithField("sid", pge.Getsid()).Info("Starting new session... ")
94-
if cmdOpts.Connection.Timeout > 0 { // Timeout less than 0 allows endless connection attempts
95-
connctx, conncancel = context.WithTimeout(ctx, time.Duration(cmdOpts.Connection.Timeout)*time.Second)
96-
defer conncancel()
97-
}
98-
9991
config := pge.getPgxConnConfig()
100-
if err = retry.Do(connctx, backoff, func(ctx context.Context) error {
92+
if err = retry.Do(ctx, backoff, func(ctx context.Context) error {
10193
if pge.ConfigDb, err = pgxpool.NewWithConfig(ctx, config); err == nil {
102-
err = pge.ConfigDb.Ping(connctx)
94+
err = pge.ConfigDb.Ping(ctx)
10395
}
10496
if err != nil {
10597
pge.l.WithError(err).Error("Connection failed")
@@ -140,17 +132,7 @@ func quoteIdent(s string) string {
140132

141133
// getPgxConnConfig transforms standard connestion string to pgx specific one with
142134
func (pge *PgEngine) getPgxConnConfig() *pgxpool.Config {
143-
var connstr string
144-
if pge.Connection.PgURL != "" {
145-
connstr = pge.Connection.PgURL
146-
} else {
147-
connstr = fmt.Sprintf("host='%s' port='%d' dbname='%s' sslmode='%s' user='%s'",
148-
pge.Connection.Host, pge.Connection.Port, pge.Connection.DBName, pge.Connection.SSLMode, pge.Connection.User)
149-
if pge.Connection.Password != "" {
150-
connstr += fmt.Sprintf(" password='%s'", pge.Connection.Password)
151-
}
152-
}
153-
connConfig, err := pgxpool.ParseConfig(connstr)
135+
connConfig, err := pgxpool.ParseConfig(pge.ConnStr)
154136
if err != nil {
155137
pge.l.WithError(err).Error("Cannot parse connection string")
156138
return nil

internal/pgengine/pgengine_test.go

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import (
2020
// this instance used for all engine tests
2121
var pge *pgengine.PgEngine
2222

23-
var cmdOpts *config.CmdOptions = config.NewCmdOptions("--clientname=pgengine_unit_test", "--password=somestrong")
23+
var cmdOpts *config.CmdOptions = config.NewCmdOptions("--clientname=pgengine_unit_test", "--connstr=postgresql://scheduler:somestrong@localhost/timetable")
2424

2525
// SetupTestCaseEx allows to configure the test case before execution
2626
func SetupTestCaseEx(t *testing.T, fc func(c *config.CmdOptions)) func(t *testing.T) {
@@ -49,14 +49,6 @@ func SetupTestCase(t *testing.T) func(t *testing.T) {
4949
}
5050
}
5151

52-
// setupTestRenoteDBFunc used to connect to remote postgreSQL database
53-
var setupTestRemoteDBFunc = func() (pgengine.PgxConnIface, error) {
54-
c := cmdOpts.Connection
55-
connstr := fmt.Sprintf("host='%s' port='%d' sslmode='%s' dbname='%s' user='%s' password='%s'",
56-
c.Host, c.Port, c.SSLMode, c.DBName, c.User, c.Password)
57-
return pge.GetRemoteDBConnection(context.Background(), connstr)
58-
}
59-
6052
func TestInitAndTestConfigDBConnection(t *testing.T) {
6153
teardownTestCase := SetupTestCase(t)
6254
defer teardownTestCase(t)
@@ -120,7 +112,7 @@ func TestInitAndTestConfigDBConnection(t *testing.T) {
120112
}
121113

122114
func TestFailedConnect(t *testing.T) {
123-
c := config.NewCmdOptions("-h", "fake", "-c", "pgengine_test")
115+
c := config.NewCmdOptions("--connstr='host=fake'", "-c", "pgengine_test")
124116
ctx, cancel := context.WithTimeout(context.Background(), pgengine.WaitTime*2)
125117
defer cancel()
126118
_, err := pgengine.New(ctx, *c, log.Init(config.LoggingOpts{LogLevel: "error"}))
@@ -191,12 +183,12 @@ func TestGetRemoteDBTransaction(t *testing.T) {
191183
teardownTestCase := SetupTestCase(t)
192184
defer teardownTestCase(t)
193185
ctx := context.Background()
194-
remoteDb, err := setupTestRemoteDBFunc()
186+
remoteDb, err := pge.GetRemoteDBConnection(context.Background(), cmdOpts.ConnStr)
195187
defer pge.FinalizeDBConnection(ctx, remoteDb)
196188
require.NoError(t, err, "remoteDB should be initialized")
197189
require.NotNil(t, remoteDb, "remoteDB should be initialized")
198190

199-
assert.NoError(t, pge.SetRole(ctx, remoteDb, pgtype.Text{String: cmdOpts.Connection.User, Valid: true}),
191+
assert.NoError(t, pge.SetRole(ctx, remoteDb, pgtype.Text{String: "scheduler", Valid: true}),
200192
"Set Role failed")
201193
assert.NotPanics(t, func() { pge.ResetRole(ctx, remoteDb) }, "Reset Role failed")
202194
pge.FinalizeDBConnection(ctx, remoteDb)

internal/scheduler/scheduler_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ var pge *pgengine.PgEngine
1717

1818
// SetupTestCase used to connect and to initialize test PostgreSQL database
1919
func SetupTestCase(t *testing.T) func(t *testing.T) {
20-
cmdOpts := config.NewCmdOptions("-c", "pgengine_unit_test", "--password=somestrong")
20+
cmdOpts := config.NewCmdOptions("-c", "pgengine_unit_test", "--connstr=postgresql://scheduler:somestrong@localhost/timetable")
2121
t.Log("Setup test case")
2222
timeout := time.After(6 * time.Second)
2323
done := make(chan bool)

0 commit comments

Comments
 (0)