Wersja inicjalna
This commit is contained in:
75
cfg/config.go
Normal file
75
cfg/config.go
Normal file
@ -0,0 +1,75 @@
|
||||
package cfg
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Connection struct {
|
||||
Host string `json:"Host,omitempty"`
|
||||
User string `json:"User,omitempty"`
|
||||
Port uint `json:"Port,omitempty"`
|
||||
DbName string `json:"DbName,omitempty"`
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
PassFile string `json:"Passfile"`
|
||||
PsqlExec string `json:"PsqlExec"`
|
||||
SqlDir string `json:"SqlDir"`
|
||||
Defaults Connection `json:"Defaults"`
|
||||
Connections []Connection `json:"Connections"`
|
||||
}
|
||||
|
||||
func GetConfig(params Parameters) (config Config, err error) {
|
||||
bytes, err := os.ReadFile(params.ConfigFile)
|
||||
if err != nil {
|
||||
return config, fmt.Errorf("błąd odczytu pliku konfiguracji: %w", err)
|
||||
}
|
||||
err = json.Unmarshal(bytes, &config)
|
||||
if err != nil {
|
||||
return config, fmt.Errorf("błąd parsowania pliku konfiguracji: %w", err)
|
||||
}
|
||||
if config.PassFile == "" && params.Passfile != "" {
|
||||
config.PassFile = params.Passfile
|
||||
}
|
||||
if config.PassFile == "" {
|
||||
return config, fmt.Errorf("nie podano Passfile (dodaj w konfiguracji lub użyj flag --passfile)")
|
||||
}
|
||||
|
||||
if config.SqlDir == "" && params.SqlDir != "" {
|
||||
config.SqlDir = params.SqlDir
|
||||
}
|
||||
|
||||
err = fixConnections(&config)
|
||||
return config, err
|
||||
}
|
||||
|
||||
func fixConnections(config *Config) error {
|
||||
def := config.Defaults
|
||||
for i := range config.Connections {
|
||||
con := &config.Connections[i]
|
||||
|
||||
if con.DbName == "" {
|
||||
con.DbName = def.DbName
|
||||
}
|
||||
if con.User == "" {
|
||||
con.User = def.User
|
||||
}
|
||||
if con.Host == "" {
|
||||
con.Host = def.Host
|
||||
}
|
||||
if con.Port == 0 {
|
||||
if def.Port != 0 {
|
||||
con.Port = def.Port
|
||||
} else {
|
||||
con.Port = 5432 // domyślny dla PostgreSQL
|
||||
}
|
||||
}
|
||||
if con.DbName == "" || con.Host == "" || con.User == "" {
|
||||
return fmt.Errorf("opis połączenia z pozycji %d jest niekompletny: %#v", i+1, con)
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
112
cfg/params.go
Normal file
112
cfg/params.go
Normal file
@ -0,0 +1,112 @@
|
||||
package cfg
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Parameters struct {
|
||||
Verbose bool
|
||||
ConfigFile string
|
||||
Passfile string
|
||||
OutDir string
|
||||
SqlDir string
|
||||
}
|
||||
|
||||
var params Parameters
|
||||
|
||||
func init() {
|
||||
flag.BoolVar(¶ms.Verbose, "verbose", false, "Dodatkowe komunkaty diagnostyczne")
|
||||
flag.StringVar(¶ms.ConfigFile, "config", "multisql.conf", "Plik konfiguracji")
|
||||
flag.StringVar(¶ms.Passfile, "passfile", "", "Plik pgpass z hasłami do baz")
|
||||
flag.StringVar(¶ms.OutDir, "outdir", "", "Katalog (istniejący i z prawem do zapisu), do którego generowane są wyniki")
|
||||
flag.StringVar(¶ms.SqlDir, "sqldir", "scripts", "Katalog, w którym znajdują się skrypty do uruchomienia")
|
||||
flag.Usage = printUsage
|
||||
flag.Parse()
|
||||
}
|
||||
func GetParams() Parameters {
|
||||
return params
|
||||
}
|
||||
|
||||
func printUsage() {
|
||||
fmt.Fprintf(os.Stderr,
|
||||
`
|
||||
multisql - uruchamia zestaw skryptów na skonfigurowanej liście baz danych.
|
||||
|
||||
Program, dla każdej z baz wskazanych w konfiguracji, uruchamia kolejno każdy
|
||||
z plików sql wskazanych parametrem lub w pliku konfiguracji poprzez
|
||||
uruchomienie narzędzia psql:
|
||||
|
||||
psql -f skrypt.sql -w -L log.txt _szczegóły_połaczenia_ 2>stderr.txt > stdout.txt
|
||||
|
||||
Skrypty mogą mieć dowolne rozszerzenia ale podkatalogi nie są obsługiwane.
|
||||
Pliki wynikowe zapisywane są do katalogu wskazanego w outdir w strukturze o postaci
|
||||
output:
|
||||
-> data-godzina-pid
|
||||
-> host-port-baza-user
|
||||
-> skrypt.sql
|
||||
-> log.txt
|
||||
-> stdout.txt
|
||||
-> stderr.txt
|
||||
|
||||
|
||||
Użycie:
|
||||
multisql -outdir /tmp -sqldir /data/skrypty -passfile ./hasla
|
||||
|
||||
Opis flag:
|
||||
`,
|
||||
)
|
||||
flag.PrintDefaults()
|
||||
fmt.Fprintf(os.Stderr,
|
||||
`
|
||||
Plik passfile ma standardowy format .pgpass PostgreSQLa.
|
||||
|
||||
Plik multisql.conf ma format JSON, np:
|
||||
> `,
|
||||
)
|
||||
|
||||
c := Config{
|
||||
PassFile: "mypgpass",
|
||||
PsqlExec: "/usr/local/bin/psql",
|
||||
SqlDir: "/data/skrypty-sql",
|
||||
Defaults: Connection{
|
||||
Port: 5433,
|
||||
User: "myapp",
|
||||
DbName: "moja-db",
|
||||
},
|
||||
Connections: []Connection{
|
||||
{
|
||||
Host: "10.20.30.01",
|
||||
},
|
||||
{
|
||||
Host: "10.20.30.02",
|
||||
DbName: "innadb",
|
||||
User: "innyuser",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
b, _ := json.Marshal(&c)
|
||||
var out bytes.Buffer
|
||||
_ = json.Indent(&out, b, "> ", "\t")
|
||||
_, _ = out.WriteTo(os.Stderr)
|
||||
|
||||
fmt.Fprintln(os.Stderr, `
|
||||
|
||||
PsqlExec jest opcjonalny - jesli nie zostanie podany wyszukuje się programu psql.exe w PATH.
|
||||
|
||||
Każde połączenie w tablicy Connections może zawierać Host, Port, User i DbName.
|
||||
Brakujące wartości są uzupełniane z sekcji Defaults (która ma taki sam
|
||||
format jak obiekt w Connections).
|
||||
|
||||
Parametry mają pierwszeństwo przed wartościami w konfiguracji.
|
||||
|
||||
Format pliku passfile jest następujący:
|
||||
|
||||
hostname:port:database:username:password
|
||||
|
||||
W szczególach opisano go na https://www.postgresql.org/docs/current/libpq-pgpass.html.`)
|
||||
}
|
Reference in New Issue
Block a user