@@ -3,13 +3,12 @@ package splunk
33import (
44 "context"
55 "crypto/tls"
6- "fmt"
76 "net/http"
7+ "reflect"
88 "strings"
99 "sync"
1010 "time"
1111
12- "github.com/hashicorp/errwrap"
1312 "github.com/hashicorp/vault/logical"
1413 "github.com/hashicorp/vault/logical/framework"
1514 "github.com/splunk/vault-plugin-splunk/clients/splunk"
@@ -25,80 +24,77 @@ func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend,
2524}
2625
2726func newBackend () logical.Backend {
28- var b backend
27+ b := backend {}
2928 b .Backend = & framework.Backend {
3029 Help : strings .TrimSpace (backendHelp ),
3130 PathsSpecial : & logical.Paths {
3231 SealWrapStorage : []string {
33- "config/root " ,
32+ "config/* " ,
3433 },
3534 },
3635 Paths : []* framework.Path {
37- b .pathConfigRoot (),
38- b .pathConfigRotateRoot (),
36+ b .pathConfigConnection (),
37+ b .pathConnectionsList (),
38+ b .pathResetConnection (),
39+ b .pathRotateRoot (),
40+ b .pathRolesList (),
3941 b .pathRoles (),
40- b .pathListRoles (),
4142 b .pathCredsCreate (),
4243 },
4344 Secrets : []* framework.Secret {
4445 b .pathSecretCreds (),
4546 },
47+ // Clean: XXXX
48+ // Invalidate: XXXX
4649 BackendType : logical .TypeLogical ,
4750 }
51+ b .connections = make (map [string ]* splunk.API )
4852 return & b
4953}
5054
5155type backend struct {
5256 * framework.Backend
53-
5457 // Mutex to protect access to Splunk clients and client configs
55- clientMutex sync.RWMutex
56- splunkAPI * splunk.API
58+ sync.RWMutex
59+ connections map [ string ] * splunk.API
5760}
5861
59- func (b * backend ) splunkClient (ctx context.Context , s logical.Storage ) (* splunk.API , error ) {
60- b .clientMutex .RLock ()
61- if b .splunkAPI != nil {
62- b .clientMutex .RUnlock ()
63- return b .splunkAPI , nil
62+ // XXXX ensureConnection
63+ func (b * backend ) GetConnection (ctx context.Context , s logical.Storage , name string ) (* splunk.API , error ) {
64+ b .RLock ()
65+ if conn , ok := b .connections [name ]; ok {
66+ b .RUnlock ()
67+ return conn , nil
6468 }
6569
6670 // Upgrade the lock for writing
67- b .clientMutex .RUnlock ()
68- b .clientMutex .Lock ()
69- defer b .clientMutex .Unlock ()
70-
71- // check client again, in the event that a client was being created while we
72- // waited for Lock()
73- if b .splunkAPI != nil {
74- return b .splunkAPI , nil
71+ b .RUnlock ()
72+ b .Lock ()
73+ defer b .Unlock ()
74+
75+ return b .connectionUnlocked (ctx , s , name )
76+ }
77+
78+ func (b * backend ) connectionUnlocked (ctx context.Context , s logical.Storage , name string ) (* splunk.API , error ) {
79+ if conn , ok := b .connections [name ]; ok {
80+ return conn , nil
7581 }
7682
77- rawRootConfig , err := s .Get (ctx , "config/root" )
83+ // create connection
84+ config , err := b .connectionConfig (ctx , s , name )
7885 if err != nil {
7986 return nil , err
8087 }
81- if rawRootConfig == nil {
82- return nil , fmt .Errorf ("no configuration found for config/root" )
83- }
84- var config rootConfig
85- if err := rawRootConfig .DecodeJSON (& config ); err != nil {
86- return nil , errwrap .Wrapf ("error reading root configuration: {{err}}" , err )
87- }
88-
89- if config .Username == "" || config .BaseURL == "" {
90- return nil , fmt .Errorf ("empty username or BaseURL" )
91- }
9288
9389 p := & splunk.APIParams {
94- BaseURL : config .BaseURL ,
90+ BaseURL : config .URL ,
9591 Config : oauth2.Config {
9692 ClientID : config .Username ,
9793 ClientSecret : config .Password ,
9894 },
9995 }
10096 tr := & http.Transport {
101- TLSClientConfig : & tls.Config {InsecureSkipVerify : true }, // XXX
97+ TLSClientConfig : & tls.Config {InsecureSkipVerify : true }, // XXXX
10298 }
10399 // client is the underlying transport for API calls, including Login (for obtaining session token)
104100 client := & http.Client {
@@ -107,8 +103,44 @@ func (b *backend) splunkClient(ctx context.Context, s logical.Storage) (*splunk.
107103 }
108104 ctx = context .WithValue (context .Background (), oauth2 .HTTPClient , client )
109105
110- b .splunkAPI = p .NewAPI (ctx )
111- return b .splunkAPI , nil
106+ b .connections [name ] = p .NewAPI (ctx )
107+ return b .connections [name ], nil
108+ }
109+
110+ // ClearConnection closes the connection and
111+ // removes it from the b.connections map.
112+ func (b * backend ) ClearConnection (name string ) error {
113+ b .Lock ()
114+ defer b .Unlock ()
115+ return b .clearConnectionUnlocked (name )
116+ }
117+
118+ func (b * backend ) clearConnectionUnlocked (name string ) error {
119+ _ , ok := b .connections [name ]
120+ if ok {
121+ delete (b .connections , name )
122+ }
123+ return nil
124+ }
125+
126+ func getValue (data * framework.FieldData , op logical.Operation , key string ) (interface {}, bool ) {
127+ if raw , ok := data .GetOk (key ); ok {
128+ return raw , true
129+ }
130+ if op == logical .CreateOperation {
131+ return data .Get (key ), true
132+ }
133+ return nil , false
134+ }
135+
136+ func decodeValue (data * framework.FieldData , op logical.Operation , key string , v interface {}) error {
137+ raw , ok := getValue (data , op , key )
138+ if ok {
139+ rraw := reflect .ValueOf (raw )
140+ rv := reflect .ValueOf (v )
141+ rv .Elem ().Set (rraw )
142+ }
143+ return nil
112144}
113145
114146const backendHelp = `
0 commit comments