forked from hashicorp/vault
-
Notifications
You must be signed in to change notification settings - Fork 0
/
backend.go
135 lines (109 loc) · 3.43 KB
/
backend.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package cassandra
import (
"context"
"fmt"
"strings"
"sync"
"github.com/gocql/gocql"
"github.com/hashicorp/vault/logical"
"github.com/hashicorp/vault/logical/framework"
)
// Factory creates a new backend
func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) {
b := Backend()
if err := b.Setup(ctx, conf); err != nil {
return nil, err
}
return b, nil
}
// Backend contains the base information for the backend's functionality
func Backend() *backend {
var b backend
b.Backend = &framework.Backend{
Help: strings.TrimSpace(backendHelp),
PathsSpecial: &logical.Paths{
SealWrapStorage: []string{
"config/connection",
},
},
Paths: []*framework.Path{
pathConfigConnection(&b),
pathRoles(&b),
pathCredsCreate(&b),
},
Secrets: []*framework.Secret{
secretCreds(&b),
},
Invalidate: b.invalidate,
Clean: func(_ context.Context) {
b.ResetDB(nil)
},
BackendType: logical.TypeLogical,
}
return &b
}
type backend struct {
*framework.Backend
// Session is goroutine safe, however, since we reinitialize
// it when connection info changes, we want to make sure we
// can close it and use a new connection; hence the lock
session *gocql.Session
lock sync.Mutex
}
type sessionConfig struct {
Hosts string `json:"hosts" structs:"hosts" mapstructure:"hosts"`
Username string `json:"username" structs:"username" mapstructure:"username"`
Password string `json:"password" structs:"password" mapstructure:"password"`
TLS bool `json:"tls" structs:"tls" mapstructure:"tls"`
InsecureTLS bool `json:"insecure_tls" structs:"insecure_tls" mapstructure:"insecure_tls"`
Certificate string `json:"certificate" structs:"certificate" mapstructure:"certificate"`
PrivateKey string `json:"private_key" structs:"private_key" mapstructure:"private_key"`
IssuingCA string `json:"issuing_ca" structs:"issuing_ca" mapstructure:"issuing_ca"`
ProtocolVersion int `json:"protocol_version" structs:"protocol_version" mapstructure:"protocol_version"`
ConnectTimeout int `json:"connect_timeout" structs:"connect_timeout" mapstructure:"connect_timeout"`
TLSMinVersion string `json:"tls_min_version" structs:"tls_min_version" mapstructure:"tls_min_version"`
}
// DB returns the database connection.
func (b *backend) DB(ctx context.Context, s logical.Storage) (*gocql.Session, error) {
b.lock.Lock()
defer b.lock.Unlock()
// If we already have a DB, we got it!
if b.session != nil {
return b.session, nil
}
entry, err := s.Get(ctx, "config/connection")
if err != nil {
return nil, err
}
if entry == nil {
return nil, fmt.Errorf("configure the DB connection with config/connection first")
}
config := &sessionConfig{}
if err := entry.DecodeJSON(config); err != nil {
return nil, err
}
session, err := createSession(config, s)
// Store the session in backend for reuse
b.session = session
return session, err
}
// ResetDB forces a connection next time DB() is called.
func (b *backend) ResetDB(newSession *gocql.Session) {
b.lock.Lock()
defer b.lock.Unlock()
if b.session != nil {
b.session.Close()
}
b.session = newSession
}
func (b *backend) invalidate(_ context.Context, key string) {
switch key {
case "config/connection":
b.ResetDB(nil)
}
}
const backendHelp = `
The Cassandra backend dynamically generates database users.
After mounting this backend, configure it using the endpoints within
the "config/" path.
`