Skip to content

Commit 25f9333

Browse files
authored
Merge pull request #124 from noapinsler/master
adding db auto discovery support to postgres
2 parents 00dc6fd + 78fca62 commit 25f9333

File tree

2 files changed

+123
-0
lines changed

2 files changed

+123
-0
lines changed

job.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,49 @@ func (j *Job) updateConnections() {
243243
conn = strings.Replace(conn, "AUTHTOKEN", url.QueryEscape(token), 1)
244244
}
245245

246+
if strings.HasPrefix(conn, "postgres://") || strings.HasPrefix(conn, "pg://") {
247+
u, err := url.Parse(conn)
248+
var filteredDBs []string
249+
if err != nil {
250+
level.Error(j.log).Log("msg", "Failed to parse URL", "url", conn, "err", err)
251+
continue
252+
}
253+
if strings.Contains(u.Path, "include") || strings.Contains(u.Path, "exclude") {
254+
if strings.Contains(u.Path, "include") && strings.Contains(u.Path, "exclude") {
255+
level.Error(j.log).Log("msg", "You cannot use exclude and include:", "url", conn, "err", err)
256+
return
257+
} else {
258+
extractedPath := u.Path //save pattern
259+
u.Path = "/postgres"
260+
dsn := u.String()
261+
databases, err := listDatabases(dsn)
262+
if err != nil {
263+
level.Error(j.log).Log("msg", "Error listing databases", "url", conn, "err", err)
264+
continue
265+
}
266+
filteredDBs, err = filterDatabases(databases, extractedPath)
267+
if err != nil {
268+
level.Error(j.log).Log("msg", "Error filtering databases", "url", conn, "err", err)
269+
continue
270+
}
271+
272+
for _, db := range filteredDBs {
273+
u.Path = "/" + db // Set the path to the filtered database name
274+
newUserDSN := u.String()
275+
j.conns = append(j.conns, &connection{
276+
conn: nil,
277+
url: newUserDSN,
278+
driver: u.Scheme,
279+
host: u.Host,
280+
database: db,
281+
user: u.User.Username(),
282+
})
283+
}
284+
continue
285+
}
286+
}
287+
}
288+
246289
u, err := url.Parse(conn)
247290
if err != nil {
248291
level.Error(j.log).Log("msg", "Failed to parse URL", "url", conn, "err", err)

postgresql.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package main
2+
3+
import (
4+
"database/sql"
5+
"fmt"
6+
"regexp"
7+
"strings"
8+
9+
_ "github.com/lib/pq"
10+
)
11+
12+
const (
13+
INCLUDE_DBS = "/include:"
14+
EXCLUDE_DBS = "/exclude:"
15+
)
16+
17+
func listDatabases(connStr string) ([]string, error) {
18+
19+
db, err := sql.Open("postgres", connStr)
20+
if err != nil {
21+
return nil, err
22+
}
23+
defer db.Close()
24+
25+
rows, err := db.Query("SELECT datname FROM pg_database WHERE datistemplate = false;")
26+
if err != nil {
27+
return nil, err
28+
}
29+
defer rows.Close()
30+
31+
var databases []string
32+
for rows.Next() {
33+
var dbname string
34+
if err := rows.Scan(&dbname); err != nil {
35+
return nil, err
36+
}
37+
databases = append(databases, dbname)
38+
}
39+
40+
return databases, nil
41+
}
42+
43+
func filterDatabases(databases []string, pattern string) ([]string, error) {
44+
var filtered []string
45+
mode, dbs := parsePattern(pattern)
46+
47+
// Split the dbs string into individual patterns
48+
dbPatterns := strings.Split(dbs, ",")
49+
50+
// Process each database name against the patterns
51+
for _, dbname := range databases {
52+
include := false
53+
54+
for _, dbPattern := range dbPatterns {
55+
matched, err := regexp.MatchString(dbPattern, dbname)
56+
if err != nil {
57+
return nil, fmt.Errorf("invalid pattern: %s", dbPattern)
58+
}
59+
if matched {
60+
include = true
61+
break
62+
}
63+
}
64+
65+
if (mode == INCLUDE_DBS && include) || (mode == EXCLUDE_DBS && !include) {
66+
filtered = append(filtered, dbname)
67+
}
68+
}
69+
70+
return filtered, nil
71+
}
72+
73+
func parsePattern(pattern string) (mode string, dbs string) {
74+
if strings.HasPrefix(pattern, INCLUDE_DBS) {
75+
return INCLUDE_DBS, pattern[len(INCLUDE_DBS):]
76+
} else if strings.HasPrefix(pattern, EXCLUDE_DBS) {
77+
return EXCLUDE_DBS, pattern[len(EXCLUDE_DBS):]
78+
}
79+
return "", ""
80+
}

0 commit comments

Comments
 (0)