Skip to content

Commit a10c142

Browse files
authored
Ensure locking patterns don't prevent parallel requests (#24)
* update dependencies * Ensure locking patterns don't prevent parallel requests * update comment on lock
1 parent c3ee7c5 commit a10c142

File tree

5 files changed

+252
-66
lines changed

5 files changed

+252
-66
lines changed

connection_producer.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ type couchbaseDBConnectionProducer struct {
3030
rawConfig map[string]interface{}
3131
Type string
3232
cluster *gocb.Cluster
33-
sync.Mutex
33+
sync.RWMutex
3434
}
3535

3636
func (c *couchbaseDBConnectionProducer) secretValues() map[string]string {
@@ -41,7 +41,7 @@ func (c *couchbaseDBConnectionProducer) secretValues() map[string]string {
4141
}
4242

4343
func (c *couchbaseDBConnectionProducer) Init(ctx context.Context, initConfig map[string]interface{}, verifyConnection bool) (saveConfig map[string]interface{}, err error) {
44-
44+
// Don't let anyone read or write the config while we're using it
4545
c.Lock()
4646
defer c.Unlock()
4747

@@ -98,9 +98,10 @@ func (c *couchbaseDBConnectionProducer) Initialize(ctx context.Context, config m
9898
_, err := c.Init(ctx, config, verifyConnection)
9999
return err
100100
}
101+
101102
func (c *couchbaseDBConnectionProducer) Connection(ctx context.Context) (interface{}, error) {
102-
// This is intentionally not grabbing the lock since the calling functions (e.g. CreateUser)
103-
// are claiming it. (The locking patterns could be refactored to be more consistent/clear.)
103+
// This is intentionally not grabbing the lock since the calling functions
104+
// (e.g. CreateUser) are claiming it.
104105

105106
if !c.Initialized {
106107
return nil, connutil.ErrNotInitialized
@@ -163,7 +164,6 @@ func (c *couchbaseDBConnectionProducer) Connection(ctx context.Context) (interfa
163164

164165
// close terminates the database connection without locking
165166
func (c *couchbaseDBConnectionProducer) close() error {
166-
167167
if c.cluster != nil {
168168
if err := c.cluster.Close(&gocb.ClusterCloseOptions{}); err != nil {
169169
return err
@@ -176,6 +176,7 @@ func (c *couchbaseDBConnectionProducer) close() error {
176176

177177
// Close terminates the database connection with locking
178178
func (c *couchbaseDBConnectionProducer) Close() error {
179+
// Don't let anyone read or write the config while we're using it
179180
c.Lock()
180181
defer c.Unlock()
181182

couchbase.go

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99

1010
"github.com/couchbase/gocb/v2"
1111
"github.com/hashicorp/errwrap"
12-
hclog "github.com/hashicorp/go-hclog"
1312
"github.com/hashicorp/go-secure-stdlib/strutil"
1413
dbplugin "github.com/hashicorp/vault/sdk/database/dbplugin/v5"
1514
"github.com/hashicorp/vault/sdk/database/helper/credsutil"
@@ -87,9 +86,9 @@ func (c *CouchbaseDB) Initialize(ctx context.Context, req dbplugin.InitializeReq
8786
}
8887

8988
func (c *CouchbaseDB) NewUser(ctx context.Context, req dbplugin.NewUserRequest) (dbplugin.NewUserResponse, error) {
90-
// Grab the lock
91-
c.Lock()
92-
defer c.Unlock()
89+
// Don't let anyone write the config while we're using it
90+
c.RLock()
91+
defer c.RUnlock()
9392

9493
username, err := c.usernameProducer.Generate(req.UsernameConfig)
9594
if err != nil {
@@ -123,22 +122,15 @@ func (c *CouchbaseDB) UpdateUser(ctx context.Context, req dbplugin.UpdateUserReq
123122
}
124123

125124
func (c *CouchbaseDB) DeleteUser(ctx context.Context, req dbplugin.DeleteUserRequest) (dbplugin.DeleteUserResponse, error) {
126-
c.Lock()
127-
defer c.Unlock()
125+
// Don't let anyone write the config while we're using it
126+
c.RLock()
127+
defer c.RUnlock()
128128

129129
db, err := c.getConnection(ctx)
130130
if err != nil {
131131
return dbplugin.DeleteUserResponse{}, fmt.Errorf("failed to make connection: %w", err)
132132
}
133133

134-
// Close the database connection to ensure no new connections come in
135-
defer func() {
136-
if err := c.close(); err != nil {
137-
logger := hclog.New(&hclog.LoggerOptions{})
138-
logger.Error("defer close failed", "error", err)
139-
}
140-
}()
141-
142134
// Get the UserManager
143135
mgr := db.Users()
144136

@@ -191,22 +183,15 @@ func newUser(ctx context.Context, db *gocb.Cluster, username string, req dbplugi
191183
}
192184

193185
func (c *CouchbaseDB) changeUserPassword(ctx context.Context, username, password string) error {
194-
c.Lock()
195-
defer c.Unlock()
186+
// Don't let anyone write the config while we're using it
187+
c.RLock()
188+
defer c.RUnlock()
196189

197190
db, err := c.getConnection(ctx)
198191
if err != nil {
199192
return err
200193
}
201194

202-
// Close the database connection to ensure no new connections come in
203-
defer func() {
204-
if err := c.close(); err != nil {
205-
logger := hclog.New(&hclog.LoggerOptions{})
206-
logger.Error("defer close failed", "error", err)
207-
}
208-
}()
209-
210195
// Get the UserManager
211196
mgr := db.Users()
212197
user, err := mgr.GetUser(username, nil)

couchbase_test.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import (
1111

1212
dbplugin "github.com/hashicorp/vault/sdk/database/dbplugin/v5"
1313
dbtesting "github.com/hashicorp/vault/sdk/database/dbplugin/v5/testing"
14-
"github.com/ory/dockertest"
15-
dc "github.com/ory/dockertest/docker"
14+
"github.com/ory/dockertest/v3"
15+
dc "github.com/ory/dockertest/v3/docker"
1616
"github.com/stretchr/testify/require"
1717
)
1818

@@ -181,7 +181,6 @@ func TestDriver(t *testing.T) {
181181
}
182182

183183
func testGetCouchbaseVersion(t *testing.T, address string) {
184-
185184
var err error
186185
pre6dot5, err = CheckForOldCouchbaseVersion(address, adminUsername, adminPassword)
187186
if err != nil {
@@ -191,7 +190,6 @@ func testGetCouchbaseVersion(t *testing.T, address string) {
191190
}
192191

193192
func setupCouchbaseDBInitialize(t *testing.T, connectionDetails map[string]interface{}) (err error) {
194-
195193
initReq := dbplugin.InitializeRequest{
196194
Config: connectionDetails,
197195
VerifyConnection: true,
@@ -213,6 +211,7 @@ func setupCouchbaseDBInitialize(t *testing.T, connectionDetails map[string]inter
213211
}
214212
return nil
215213
}
214+
216215
func testCouchbaseDBInitialize_TLS(t *testing.T, address string, port int) {
217216
t.Log("Testing TLS Init()")
218217

@@ -242,6 +241,7 @@ func testCouchbaseDBInitialize_TLS(t *testing.T, address string, port int) {
242241
t.Log("Testing TLS Init() failed as expected (no BucketName set)")
243242
}
244243
}
244+
245245
func testCouchbaseDBInitialize_NoTLS(t *testing.T, address string, port int) {
246246
t.Log("Testing plain text Init()")
247247

@@ -258,8 +258,8 @@ func testCouchbaseDBInitialize_NoTLS(t *testing.T, address string, port int) {
258258
if err != nil && pre6dot5 {
259259
t.Log("Testing TLS Init() failed as expected (no BucketName set)")
260260
}
261-
262261
}
262+
263263
func testCouchbaseDBInitialize_Pre6dot5TLS(t *testing.T, address string, port int) {
264264
t.Log("Testing TLS Pre 6.5 Init()")
265265

@@ -287,6 +287,7 @@ func testCouchbaseDBInitialize_Pre6dot5TLS(t *testing.T, address string, port in
287287
}
288288
setupCouchbaseDBInitialize(t, connectionDetails)
289289
}
290+
290291
func testCouchbaseDBInitialize_Pre6dot5NoTLS(t *testing.T, address string, port int) {
291292
t.Log("Testing Pre 6.5 Init()")
292293

@@ -613,6 +614,7 @@ func testCouchbaseDBCreateUser_groupOnly(t *testing.T, address string, port int)
613614
t.Fatalf("Could not revoke user: %s", userResp.Username)
614615
}
615616
}
617+
616618
func testCouchbaseDBCreateUser_roleAndGroup(t *testing.T, address string, port int) {
617619
if pre6dot5 {
618620
t.Log("Skipping as groups are not supported pre6.5.0")
@@ -676,6 +678,7 @@ func testCouchbaseDBCreateUser_roleAndGroup(t *testing.T, address string, port i
676678
t.Fatalf("Could not revoke user: %s", userResp.Username)
677679
}
678680
}
681+
679682
func testCouchbaseDBRotateRootCredentials(t *testing.T, address string, port int) {
680683
t.Log("Testing RotateRootCredentials()")
681684

@@ -727,7 +730,6 @@ func testCouchbaseDBRotateRootCredentials(t *testing.T, address string, port int
727730
}
728731

729732
func doCouchbaseDBSetCredentials(t *testing.T, username, password, address string, port int) {
730-
731733
t.Log("Testing SetCredentials()")
732734

733735
connectionDetails := map[string]interface{}{

go.mod

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,69 @@ module github.com/hashicorp/vault-plugin-database-couchbase
33
go 1.14
44

55
require (
6-
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
76
github.com/cenkalti/backoff v2.2.1+incompatible
8-
github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe // indirect
7+
github.com/containerd/continuity v0.2.0 // indirect
98
github.com/couchbase/gocb/v2 v2.3.1
10-
github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect
9+
github.com/docker/cli v20.10.9+incompatible // indirect
10+
github.com/docker/docker v20.10.9+incompatible // indirect
1111
github.com/hashicorp/errwrap v1.0.0
1212
github.com/hashicorp/go-hclog v0.14.1
1313
github.com/hashicorp/go-secure-stdlib/strutil v0.1.1
1414
github.com/hashicorp/go-version v1.2.1
1515
github.com/hashicorp/vault/sdk v0.1.14-0.20210204230556-cf85a862b7c6
1616
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d // indirect
1717
github.com/lib/pq v1.8.0 // indirect
18-
github.com/mitchellh/mapstructure v1.3.3
19-
github.com/ory/dockertest v3.3.5+incompatible
20-
github.com/sirupsen/logrus v1.6.0 // indirect
18+
github.com/mitchellh/mapstructure v1.4.2
19+
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
20+
github.com/ory/dockertest/v3 v3.8.0
2121
github.com/stretchr/testify v1.7.0
22+
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
23+
golang.org/x/net v0.0.0-20211008194852-3b03d305991f // indirect
24+
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac // indirect
25+
gopkg.in/yaml.v2 v2.4.0 // indirect
26+
)
27+
28+
require (
29+
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
30+
github.com/Microsoft/go-winio v0.5.0 // indirect
31+
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
32+
github.com/armon/go-metrics v0.3.3 // indirect
33+
github.com/cenkalti/backoff/v4 v4.1.1 // indirect
34+
github.com/couchbase/gocbcore/v10 v10.0.2 // indirect
35+
github.com/davecgh/go-spew v1.1.1 // indirect
36+
github.com/docker/go-connections v0.4.0 // indirect
37+
github.com/docker/go-units v0.4.0 // indirect
38+
github.com/fatih/color v1.7.0 // indirect
39+
github.com/gogo/protobuf v1.3.2 // indirect
40+
github.com/golang/protobuf v1.5.0 // indirect
41+
github.com/golang/snappy v0.0.1 // indirect
42+
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
43+
github.com/google/uuid v1.1.1 // indirect
44+
github.com/hashicorp/go-immutable-radix v1.1.0 // indirect
45+
github.com/hashicorp/go-multierror v1.1.0 // indirect
46+
github.com/hashicorp/go-plugin v1.0.1 // indirect
47+
github.com/hashicorp/go-sockaddr v1.0.2 // indirect
48+
github.com/hashicorp/go-uuid v1.0.2 // indirect
49+
github.com/hashicorp/golang-lru v0.5.3 // indirect
50+
github.com/imdario/mergo v0.3.12 // indirect
51+
github.com/mattn/go-colorable v0.1.6 // indirect
52+
github.com/mattn/go-isatty v0.0.12 // indirect
53+
github.com/mitchellh/go-testing-interface v1.0.0 // indirect
54+
github.com/oklog/run v1.0.0 // indirect
55+
github.com/opencontainers/go-digest v1.0.0 // indirect
56+
github.com/opencontainers/image-spec v1.0.1 // indirect
57+
github.com/opencontainers/runc v1.0.2 // indirect
58+
github.com/pierrec/lz4 v2.5.2+incompatible // indirect
59+
github.com/pkg/errors v0.9.1 // indirect
60+
github.com/pmezard/go-difflib v1.0.0 // indirect
61+
github.com/ryanuber/go-glob v1.0.0 // indirect
62+
github.com/sirupsen/logrus v1.8.1 // indirect
63+
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
64+
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
65+
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect
66+
golang.org/x/text v0.3.6 // indirect
67+
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
68+
google.golang.org/grpc v1.29.1 // indirect
69+
google.golang.org/protobuf v1.26.0 // indirect
70+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
2271
)

0 commit comments

Comments
 (0)