Skip to content
This repository was archived by the owner on Mar 15, 2024. It is now read-only.

Commit 2983331

Browse files
authored
Merge pull request #23 from splunk/mw/te-183-pagination
TE-183 pagination
2 parents 4780e70 + c1d5112 commit 2983331

File tree

8 files changed

+721
-13
lines changed

8 files changed

+721
-13
lines changed

.circleci/config.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ jobs:
2424
command: make lint
2525
- run:
2626
name: Wait for Splunk Container
27-
command: curl -4sSk --retry 40 --retry-connrefused --retry-delay 3 -o /dev/null ${SPLUNK_ADDR}
27+
command: |
28+
curl -4sSk --retry 40 --retry-connrefused --retry-delay 3 -o /dev/null ${SPLUNK_ADDR}
29+
sleep 5
30+
curl -4sSk --retry 40 --retry-connrefused --retry-delay 3 -o /dev/null ${SPLUNK_ADDR}
2831
- run:
2932
name: Test
3033
command: make test TESTREPORT=test-results/go/results.xml

clients/splunk/deployment.go

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,21 @@ func newDeploymentService(client *Client) *DeploymentService {
1111
}
1212
}
1313

14-
// GetSearchPeers returns information about all search peers
15-
func (d *DeploymentService) GetSearchPeers() ([]ServerInfoEntry, *Response, error) {
16-
info := make([]ServerInfoEntry, 0)
17-
resp, err := Receive(d.client.New().Get("search/distributed/peers"), &info)
14+
var (
15+
ServerInfoEntryFilterDefault *PaginationFilter
16+
17+
ServerInfoEntryFilterMinimal *PaginationFilter = &PaginationFilter{
18+
Filter: []string{"host", "host_fqdn", "server_roles"},
19+
}
20+
)
21+
22+
// SearchPeers returns information about all search peers
23+
func (d *DeploymentService) SearchPeers(filter *PaginationFilter) ([]ServerInfoEntry, *Response, error) {
24+
var info []ServerInfoEntry
25+
sling := d.client.New().Get("search/distributed/peers")
26+
if filter != ServerInfoEntryFilterDefault {
27+
sling = sling.QueryStruct(filter)
28+
}
29+
resp, err := Receive(sling, &info)
1830
return info, resp, err
1931
}

clients/splunk/splunk.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,26 @@ import (
77
"time"
88
)
99

10+
// API https://docs.splunk.com/Documentation/Splunk/8.0.2/RESTREF/RESTprolog#Request_and_response_details
11+
type PaginationFilter struct {
12+
Count int `url:"count,omitempty"` // NOTE: we omit zero value, since this is already set in outputMode
13+
Filter []string `url:"f,omitempty"`
14+
Offset int `url:"offset,omitempty"`
15+
Search string `url:"search,omitempty"`
16+
SortDir string `url:"sort_dir,omitempty"`
17+
SortKey string `url:"sort_key,omitempty"`
18+
SortMode string `url:"sort_mode,omitempty"`
19+
Summarize bool `url:"summarize,omitempty"`
20+
}
21+
1022
type outputMode struct {
11-
Mode string `url:"output_mode"`
23+
Mode string `url:"output_mode,omitempty"`
24+
// by default, we do not want any pagination,
25+
// override with PaginationFilter
26+
Count int `url:"count"`
1227
}
1328

14-
var jsonOutputMode = outputMode{"json"}
29+
var jsonOutputMode = outputMode{"json", 0}
1530

1631
// API https://docs.splunk.com/Documentation/Splunk/latest/RESTREF/RESTprolog
1732
type API struct {

conn.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,12 @@ func (config *splunkConfig) newConnection(ctx context.Context) (*splunk.API, err
151151
if err != nil {
152152
return nil, err
153153
}
154+
154155
tr := &http.Transport{
155156
TLSClientConfig: tlsConfig,
157+
Proxy: http.ProxyFromEnvironment,
156158
}
159+
157160
// client is the underlying transport for API calls, including Login (for obtaining session token)
158161
client := &http.Client{
159162
Transport: tr,

path_creds_create.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package splunk
33
import (
44
"context"
55
"fmt"
6+
"strings"
67

78
"github.com/hashicorp/errwrap"
89
uuid "github.com/hashicorp/go-uuid"
@@ -127,7 +128,7 @@ func (b *backend) credsReadHandlerStandalone(ctx context.Context, req *logical.R
127128
func findNode(nodeFQDN string, hosts []splunk.ServerInfoEntry, roleConfig *roleConfig) (bool, error) {
128129
for _, host := range hosts {
129130
// check if node_fqdn is in either of HostFQDN or Host. User might not always the FQDN on the cli input
130-
if host.Content.HostFQDN == nodeFQDN || host.Content.Host == nodeFQDN {
131+
if strings.EqualFold(host.Content.HostFQDN, nodeFQDN) || strings.EqualFold(host.Content.Host, nodeFQDN) {
131132
// Return true if the requested node type is allowed
132133
if strutil.StrListContains(roleConfig.AllowedServerRoles, "*") {
133134
return true, nil
@@ -174,11 +175,12 @@ func (b *backend) credsReadHandlerMulti(ctx context.Context, req *logical.Reques
174175
return nil, err
175176
}
176177

177-
nodes, _, err := conn.Deployment.GetSearchPeers()
178+
nodes, _, err := conn.Deployment.SearchPeers(splunk.ServerInfoEntryFilterMinimal)
178179
if err != nil {
179-
b.Logger().Error("Error while reading SearchPeers from cluster master", err)
180+
b.Logger().Error("Error while reading SearchPeers from cluster master", "err", err)
180181
return nil, errwrap.Wrapf("unable to read searchpeers from cluster master: {{err}}", err)
181182
}
183+
182184
_, err = findNode(nodeFQDN, nodes, role)
183185
if err != nil {
184186
return nil, err
@@ -242,10 +244,10 @@ func (b *backend) credsReadHandler(ctx context.Context, req *logical.Request, d
242244
node_fqdn, present := d.GetOk("node_fqdn")
243245
// if node_fqdn is specified then the treat the request for a multi-node deployment
244246
if present {
245-
b.Logger().Debug(fmt.Sprintf("node_fqdn: [%s] specified for role: [%s]. using clustered mode getting temporary creds", node_fqdn.(string), name))
247+
b.Logger().Debug("node_fqdn specified for role. using clustered mode for getting temporary creds", "nodeFQDN", node_fqdn.(string), "role", name)
246248
return b.credsReadHandlerMulti(ctx, req, d)
247249
}
248-
b.Logger().Debug(fmt.Sprintf("node_fqdn not specified for role: [%s]. using standalone mode getting temporary creds", name))
250+
b.Logger().Debug("node_fqdn not specified for role. using standalone mode for getting temporary creds", "role", name)
249251
return b.credsReadHandlerStandalone(ctx, req, d)
250252
}
251253

path_creds_create_test.go

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
package splunk
2+
3+
import (
4+
"encoding/json"
5+
"io/ioutil"
6+
"path/filepath"
7+
"testing"
8+
9+
"gotest.tools/assert"
10+
11+
"github.com/splunk/vault-plugin-splunk/clients/splunk"
12+
)
13+
14+
func Test_findNode(t *testing.T) {
15+
nodes := make([]splunk.ServerInfoEntry, 0)
16+
17+
gp := filepath.Join("testdata", t.Name()+".json")
18+
jsonResponseSearchDistributedPeers, err := ioutil.ReadFile(gp)
19+
assert.NilError(t, err)
20+
21+
err = json.Unmarshal(jsonResponseSearchDistributedPeers, &nodes)
22+
assert.NilError(t, err)
23+
24+
type args struct {
25+
nodeFQDN string
26+
hosts []splunk.ServerInfoEntry
27+
roleConfig *roleConfig
28+
}
29+
tests := []struct {
30+
name string
31+
args args
32+
want bool
33+
wantErr bool
34+
}{
35+
{
36+
name: "server entry first",
37+
args: args{
38+
nodeFQDN: "idm-i-074b0895939212e99.foo.example.com",
39+
hosts: nodes,
40+
roleConfig: &roleConfig{
41+
AllowedServerRoles: []string{"*"},
42+
},
43+
},
44+
want: true,
45+
wantErr: false,
46+
},
47+
{
48+
name: "server entry last",
49+
args: args{
50+
nodeFQDN: "sh-i-0a12fdd509c2a2954.foo.example.com",
51+
hosts: nodes,
52+
roleConfig: &roleConfig{
53+
AllowedServerRoles: []string{"*"},
54+
},
55+
},
56+
want: true,
57+
wantErr: false,
58+
},
59+
{
60+
name: "server entry case insensitive",
61+
args: args{
62+
nodeFQDN: "SH-I-0A12FDD509C2A2954.FOO.EXAMPLE.COM",
63+
hosts: nodes,
64+
roleConfig: &roleConfig{
65+
AllowedServerRoles: []string{"*"},
66+
},
67+
},
68+
want: true,
69+
wantErr: false,
70+
},
71+
{
72+
name: "server entry short name",
73+
args: args{
74+
nodeFQDN: "SH-I-0A12FDD509C2A2954",
75+
hosts: nodes,
76+
roleConfig: &roleConfig{
77+
AllowedServerRoles: []string{"*"},
78+
},
79+
},
80+
want: true,
81+
wantErr: false,
82+
},
83+
{
84+
name: "server entry not found",
85+
args: args{
86+
nodeFQDN: "unknown-host",
87+
hosts: nodes,
88+
roleConfig: &roleConfig{
89+
AllowedServerRoles: []string{"*"},
90+
},
91+
},
92+
want: false,
93+
wantErr: true,
94+
},
95+
{
96+
name: "role match mismatch",
97+
args: args{
98+
nodeFQDN: "sh-i-0a12fdd509c2a2954.foo.example.com",
99+
hosts: nodes,
100+
roleConfig: &roleConfig{
101+
AllowedServerRoles: []string{"unknown-role"},
102+
},
103+
},
104+
want: false,
105+
wantErr: true,
106+
},
107+
{
108+
name: "role match first",
109+
args: args{
110+
nodeFQDN: "sh-i-0a12fdd509c2a2954.foo.example.com",
111+
hosts: nodes,
112+
roleConfig: &roleConfig{
113+
AllowedServerRoles: []string{"cluster_search_head"},
114+
},
115+
},
116+
want: true,
117+
wantErr: false,
118+
},
119+
{
120+
name: "role match last",
121+
args: args{
122+
nodeFQDN: "sh-i-0a12fdd509c2a2954.foo.example.com",
123+
hosts: nodes,
124+
roleConfig: &roleConfig{
125+
AllowedServerRoles: []string{"unknown_role", "kv_store"},
126+
},
127+
},
128+
want: true,
129+
wantErr: false,
130+
},
131+
}
132+
for _, tt := range tests {
133+
t.Run(tt.name, func(t *testing.T) {
134+
got, err := findNode(tt.args.nodeFQDN, tt.args.hosts, tt.args.roleConfig)
135+
if (err != nil) != tt.wantErr {
136+
t.Errorf("findNode() error = %v, wantErr %v", err, tt.wantErr)
137+
return
138+
}
139+
if got != tt.want {
140+
t.Errorf("findNode() = %v, want %v", got, tt.want)
141+
}
142+
})
143+
}
144+
}

secret_creds.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ func (b *backend) secretCredsRevokeHandler(ctx context.Context, req *logical.Req
109109
}
110110

111111
func (b *backend) ensureNodeConnection(ctx context.Context, config *splunkConfig, nodeFQDN string) (*splunk.API, error) {
112-
b.Logger().Debug(fmt.Sprintf("connection for node_fqdn: [%s]", nodeFQDN))
112+
b.Logger().Debug("node connection", "nodeFQDN", nodeFQDN)
113113
if nodeFQDN == "" {
114114
return b.ensureConnection(ctx, config)
115115
}

0 commit comments

Comments
 (0)