Skip to content

Commit 2a61a86

Browse files
authored
feat(collectors): Add TLS parameters to the postgres collector (#875)
For a postgres collector spec targeting a server configured to accept (m)TLS connections we need to pass in the necessary parameters in order to successfully connect to the server. Both preflight and support bundle specs use this collector. This change allows us to pass in the necessary TLS parameters via inlined TLS configuration or via a secret reference. Fixes #747
1 parent c85bf9a commit 2a61a86

File tree

5 files changed

+125
-11
lines changed

5 files changed

+125
-11
lines changed

examples/preflight/postgres.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,3 @@ spec:
2020
message: The postgres server must be at least version 10
2121
- pass:
2222
message: The postgres connection checks out
23-

go.mod

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ require (
1818
github.com/gorilla/handlers v1.5.1
1919
github.com/hashicorp/go-getter v1.6.2
2020
github.com/hashicorp/go-multierror v1.1.1
21-
github.com/lib/pq v1.10.7
21+
github.com/jackc/pgx/v5 v5.1.1
2222
github.com/longhorn/go-iscsi-helper v0.0.0-20210330030558-49a327fb024e
2323
github.com/manifoldco/promptui v0.9.0
2424
github.com/mattn/go-isatty v0.0.16
@@ -54,6 +54,8 @@ require (
5454
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
5555
github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect
5656
github.com/googleapis/go-type-adapters v1.0.0 // indirect
57+
github.com/jackc/pgpassfile v1.0.0 // indirect
58+
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
5759
github.com/mistifyio/go-zfs/v3 v3.0.0 // indirect
5860
github.com/russross/blackfriday/v2 v2.1.0 // indirect
5961
github.com/sylabs/sif/v2 v2.8.1 // indirect

go.sum

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,12 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt
658658
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
659659
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
660660
github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA=
661+
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
662+
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
663+
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
664+
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
665+
github.com/jackc/pgx/v5 v5.1.1 h1:pZD79K1SYv8wc2HmCQA6VdmRQi7/OtCfv9bM3WAXUYA=
666+
github.com/jackc/pgx/v5 v5.1.1/go.mod h1:Ptn7zmohNsWEsdxRawMzk3gaKma2obW+NWTnKa0S4nk=
661667
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
662668
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
663669
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
@@ -711,8 +717,6 @@ github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
711717
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
712718
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
713719
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
714-
github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
715-
github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
716720
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
717721
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
718722
github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo=
@@ -803,7 +807,6 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
803807
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
804808
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
805809
github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
806-
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
807810
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
808811
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d h1:x3S6kxmy49zXVVyhcnrFqxvNVCBPb2KZ9hV2RBdS840=
809812
github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ=
@@ -1092,7 +1095,7 @@ go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee33
10921095
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o=
10931096
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
10941097
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
1095-
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
1098+
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
10961099
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
10971100
go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
10981101
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
@@ -1666,8 +1669,8 @@ gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8
16661669
gopkg.in/check.v1 v1.0.0-20160105164936-4f90aeace3a2/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
16671670
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
16681671
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
1669-
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
16701672
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
1673+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
16711674
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
16721675
gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
16731676
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=

pkg/collect/postgres.go

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@ package collect
33
import (
44
"bytes"
55
"context"
6-
"database/sql"
76
"encoding/json"
87
"fmt"
98
"regexp"
109

11-
_ "github.com/lib/pq"
10+
"github.com/jackc/pgx/v5"
1211
"github.com/pkg/errors"
1312
troubleshootv1beta2 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
1413
"k8s.io/client-go/kubernetes"
@@ -33,15 +32,54 @@ func (c *CollectPostgres) IsExcluded() (bool, error) {
3332
return isExcluded(c.Collector.Exclude)
3433
}
3534

35+
func (c *CollectPostgres) createConnectConfig() (*pgx.ConnConfig, error) {
36+
if c.Collector.URI == "" {
37+
return nil, errors.New("postgres uri cannot be empty")
38+
}
39+
40+
cfg, err := pgx.ParseConfig(c.Collector.URI)
41+
if err != nil {
42+
return nil, errors.Wrap(err, "failed to parse postgres config")
43+
}
44+
45+
if c.Collector.TLS != nil {
46+
tlsCfg, err := createTLSConfig(c.Context, c.Client, c.Collector.TLS)
47+
if err != nil {
48+
return nil, err
49+
}
50+
51+
tlsCfg.ServerName = cfg.Host
52+
cfg.TLSConfig = tlsCfg
53+
}
54+
55+
return cfg, nil
56+
}
57+
58+
func (c *CollectPostgres) connect() (*pgx.Conn, error) {
59+
connCfg, err := c.createConnectConfig()
60+
if err != nil {
61+
return nil, err
62+
}
63+
64+
conn, err := pgx.ConnectConfig(c.Context, connCfg)
65+
if err != nil {
66+
return nil, err
67+
}
68+
69+
return conn, nil
70+
}
71+
3672
func (c *CollectPostgres) Collect(progressChan chan<- interface{}) (CollectorResult, error) {
3773
databaseConnection := DatabaseConnection{}
3874

39-
db, err := sql.Open("postgres", c.Collector.URI)
75+
conn, err := c.connect()
4076
if err != nil {
4177
databaseConnection.Error = err.Error()
4278
} else {
79+
defer conn.Close(c.Context)
80+
4381
query := `select version()`
44-
row := db.QueryRow(query)
82+
row := conn.QueryRow(c.Context, query)
4583
version := ""
4684
if err := row.Scan(&version); err != nil {
4785
databaseConnection.Error = err.Error()

pkg/collect/postgres_test.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package collect
22

33
import (
4+
"context"
45
"testing"
56

7+
"github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta2"
68
"github.com/stretchr/testify/assert"
79
"github.com/stretchr/testify/require"
10+
testclient "k8s.io/client-go/kubernetes/fake"
811
)
912

1013
func Test_parsePostgresVersion(t *testing.T) {
@@ -44,3 +47,72 @@ func Test_parsePostgresVersion(t *testing.T) {
4447
})
4548
}
4649
}
50+
51+
func TestCollectPostgres_createConnectConfigPlainText(t *testing.T) {
52+
tests := []struct {
53+
name string
54+
uri string
55+
hasError bool
56+
}{
57+
{
58+
name: "valid uri creates postgres connection config successfully",
59+
uri: "postgresql://user:password@my-pghost:5432/defaultdb?sslmode=require",
60+
},
61+
{
62+
name: "empty uri fails to create postgres connection config with error",
63+
uri: "",
64+
hasError: true,
65+
},
66+
{
67+
name: "invalid redis protocol fails to create postgres connection config with error",
68+
uri: "http://somehost:5432",
69+
hasError: true,
70+
},
71+
}
72+
for _, tt := range tests {
73+
t.Run(tt.name, func(t *testing.T) {
74+
c := &CollectPostgres{
75+
Context: context.Background(),
76+
Collector: &v1beta2.Database{
77+
URI: tt.uri,
78+
},
79+
}
80+
81+
connCfg, err := c.createConnectConfig()
82+
assert.Equal(t, err != nil, tt.hasError)
83+
if err == nil {
84+
require.NotNil(t, connCfg)
85+
assert.Equal(t, connCfg.Host, "my-pghost")
86+
assert.Equal(t, connCfg.Database, "defaultdb")
87+
} else {
88+
t.Log(err)
89+
assert.Nil(t, connCfg)
90+
}
91+
})
92+
}
93+
}
94+
95+
func TestCollectPostgres_createConnectConfigTLS(t *testing.T) {
96+
k8sClient := testclient.NewSimpleClientset()
97+
98+
c := &CollectPostgres{
99+
Client: k8sClient,
100+
Context: context.Background(),
101+
Collector: &v1beta2.Database{
102+
URI: "postgresql://user:password@my-pghost:5432/defaultdb?sslmode=require",
103+
TLS: &v1beta2.TLSParams{
104+
CACert: getTestFixture(t, "db/ca.pem"),
105+
ClientCert: getTestFixture(t, "db/client.pem"),
106+
ClientKey: getTestFixture(t, "db/client-key.pem"),
107+
},
108+
},
109+
}
110+
111+
connCfg, err := c.createConnectConfig()
112+
assert.NoError(t, err)
113+
assert.NotNil(t, connCfg)
114+
assert.Equal(t, connCfg.Host, "my-pghost")
115+
assert.NotNil(t, connCfg.TLSConfig.Certificates)
116+
assert.NotNil(t, connCfg.TLSConfig.RootCAs)
117+
assert.False(t, connCfg.TLSConfig.InsecureSkipVerify)
118+
}

0 commit comments

Comments
 (0)