feat: Dodane parsowanie pliku pgpass

pgpass jest prsowany i przy uruchomieniu psql podawane jest
wybrane hasło pasujące do połaczenia
This commit is contained in:
Rychliński Arkadiusz 2022-11-22 15:43:54 +01:00
parent c34954ef14
commit 7d9c3d8f62
4 changed files with 114 additions and 31 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
/.vscode
/output
/pgpass

View File

@ -9,6 +9,7 @@ import (
"time"
"baal.ar76.eu/x/pub/multisql/cfg"
"baal.ar76.eu/x/pub/multisql/pass"
"baal.ar76.eu/x/pub/multisql/psql"
)
@ -69,6 +70,15 @@ func (self Manager) Run() error {
return err
}
var passdb *pass.PassDb
if self.config.PassFile != "" {
passdb, err = pass.Load(self.config.PassFile, "TODO")
if err != nil {
return err
}
}
var group sync.WaitGroup
for _, con := range self.config.Connections {
@ -84,7 +94,7 @@ func (self Manager) Run() error {
go self.Logger(&group, stream, con)
sql := psql.Create(
self.config.PassFile,
passdb,
dbDir,
scripts,
con,

81
pass/pass.go Normal file
View File

@ -0,0 +1,81 @@
package pass
import (
"bytes"
"fmt"
"os"
)
type pgpassrow struct {
hostname string
port string
database string
username string
password string
}
type PassDb struct {
db []pgpassrow
cache map[string]*pgpassrow
}
func Load(file string, master string) (*PassDb, error) {
data, err := os.ReadFile(file)
if err != nil {
return nil, err
}
lines := bytes.Split(data, []byte{'\n'})
var rows []pgpassrow
for i, line := range lines {
line = bytes.TrimRight(line, "\n\r \t")
if len(line) == 0 || line[0] == byte('#') {
continue
}
fields := bytes.Split(line, []byte{':'})
if len(fields) != 5 {
return nil, fmt.Errorf("błąd w pliku hasłeł %s:%d: niewłaściwa liczba pól", file, i)
}
rows = append(rows, pgpassrow{
hostname: string(fields[0]),
port: string(fields[1]),
database: string(fields[2]),
username: string(fields[3]),
password: string(fields[4]),
})
}
return &PassDb{
db: rows,
cache: make(map[string]*pgpassrow),
}, nil
}
func match(value string, pattern string) bool {
return pattern == "*" || pattern == value
}
func (self *PassDb) FindPassword(host string, port uint, database string, user string) string {
myport := fmt.Sprintf("%d", port)
key := fmt.Sprintf("%s:%s:%s:%s", host, myport, database, user)
cached, ok := self.cache[key]
if ok {
return cached.password
}
// pierwszy pasujący do wzorca
for i := range self.db {
if match(host, self.db[i].hostname) &&
match(myport, self.db[i].port) &&
match(database, self.db[i].database) &&
match(user, self.db[i].username) {
self.cache[key] = &self.db[i]
return self.db[i].password
}
}
return ""
}

View File

@ -10,15 +10,16 @@ import (
"runtime"
"baal.ar76.eu/x/pub/multisql/cfg"
"baal.ar76.eu/x/pub/multisql/pass"
)
type Instance struct {
outdir string
scripts []string
passfile string
psqlExe string
conn cfg.Connection
verbose bool
outdir string
scripts []string
pasdb *pass.PassDb
psqlExe string
conn cfg.Connection
verbose bool
}
type Result struct {
@ -26,32 +27,22 @@ type Result struct {
Err error
}
func Create(passfile string, outdir string, scripts []string, conn cfg.Connection, psqlExe string, verbose bool) (instnace Instance) {
func Create(passdb *pass.PassDb, outdir string, scripts []string, conn cfg.Connection, psqlExe string, verbose bool) (instnace Instance) {
instnace = Instance{
outdir: outdir,
scripts: scripts,
passfile: passfile,
conn: conn,
psqlExe: psqlExe,
verbose: verbose,
outdir: outdir,
scripts: scripts,
pasdb: passdb,
conn: conn,
psqlExe: psqlExe,
verbose: verbose,
}
return instnace
}
func (self Instance) Exec(result chan<- Result) {
absPassFile := ""
if self.passfile != "" {
var err error
absPassFile, err = filepath.Abs(self.passfile)
if err != nil {
result <- Result{
Script: "*",
Err: fmt.Errorf("problem ze zbudowaniem ściężki do pliku haseł: %w", err),
}
return
}
}
connString := fmt.Sprintf("host=%s port=%d dbname=%s user=%s", self.conn.Host, self.conn.Port, self.conn.DbName, self.conn.User)
for _, scr := range self.scripts {
@ -65,7 +56,8 @@ func (self Instance) Exec(result chan<- Result) {
}
continue
}
err = self.cmdPsql(outdir, connString, scr, absPassFile)
password := self.pasdb.FindPassword(self.conn.Host, self.conn.Port, self.conn.DbName, self.conn.User)
err = self.cmdPsql(outdir, connString, scr, password)
result <- Result{
Script: scr,
Err: err,
@ -74,7 +66,7 @@ func (self Instance) Exec(result chan<- Result) {
close(result)
}
func (self Instance) cmdPsql(outdir string, connString string, script string, passfile string) error {
func (self Instance) cmdPsql(outdir string, connString string, script string, password string) error {
absScript, err := filepath.Abs(script)
if err != nil {
return fmt.Errorf("problem ze zbudowaniem ściezki do skryptu: %w", err)
@ -112,13 +104,12 @@ func (self Instance) cmdPsql(outdir string, connString string, script string, pa
cmd.Stdout = fhOut
cmd.Dir = outdir
if passfile != "" {
if password != "" {
env := os.Environ()
env = append(env, "PGPASSFILE=" + passfile)
env = append(env, "PGPASSWORD="+password)
cmd.Env = env
}
if self.verbose {
log.Printf("Uruchamiam %s", cmd.String())
}