PostgreSQL

/app/lib/database/pgservice.go (2.7 KB)

  1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package database

import (
"os"
"strconv"

"github.com/go-ini/ini"
"github.com/pkg/errors"
"github.com/samber/lo"

"{{{ .Package }}}/app/util"
)

// Valid parameters supported in reading `PGSERVICEFILE`.
var validParams = map[string]string{
"host": "PGHOST",
"port": "PGPORT",
"dbname": "PGDATABASE",
"user": "PGUSER",
"password": "PGPASSWORD",
"sslmode": "PGSSLMODE",
"sslcert": "PGSSLCERT",
"sslkey": "PGSSLKEY",
"sslrootcert": "PGSSLROOTCERT",
}

type PostgresServiceParams struct {
Host string `json:"host"`
Port int `json:"port,omitempty"`
Schema string `json:"schema,omitempty"`
Username string `json:"username"`
Password string `json:"password,omitempty"`
Database string `json:"database,omitempty"`
SSLMode string `json:"sslmode,omitempty"`
SSLKey string `json:"sslkey,omitempty"`
SSLCert string `json:"sslcert,omitempty"`
SSLRootCert string `json:"sslrootcert,omitempty"`
}

// PostgresParamsFromService parses connection service config from DB_SERVICE env var from file located at DB_SERVICEFILE.
// If DB_SERVICEFILE is not provided, it searches for the pg service conf file in home directory.
func PostgresParamsFromService() (*PostgresServiceParams, error) {
pgservice := util.GetEnv("db_service")
if pgservice == "" {
return nil, errors.New("missing 'DB_SERVICE' env var")
}

pgservicefile := util.GetEnv("db_servicefile")
if pgservicefile == "" {
pgservicefile = os.ExpandEnv("${HOME}/.pg_service.conf")
}

paramMap, err := parseConfigSection(pgservice, pgservicefile)
if err != nil {
return nil, err
}

port, err := strconv.ParseInt(paramMap["port"], 10, 32)
if err != nil {
port = 5432
}
params := PostgresServiceParams{
Host: paramMap["host"],
Port: int(port),
Username: paramMap["user"],
Password: paramMap["password"],
Database: paramMap["dbname"],
SSLMode: paramMap["sslmode"],
SSLKey: paramMap["sslkey"],
SSLCert: paramMap["sslcert"],
SSLRootCert: paramMap["sslrootcert"],
}

return &params, nil
}

// parseConfigSection parses options specified in a config section of a pg service file and returns them as a map.
func parseConfigSection(service, file string) (map[string]string, error) {
result := make(map[string]string)

cfg, err := ini.Load(file)
if err != nil {
return result, errors.Errorf("error loading pg service file at '%s'", file)
}

cfg.BlockMode = false

section, err := cfg.GetSection(service)
if err != nil {
return result, err
}

lo.ForEach(lo.Keys(validParams), func(key string, _ int) {
if value, err := section.GetKey(key); err == nil {
result[key] = value.String()
}
})

return result, nil
}