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

Commit 22c8b9b

Browse files
author
Amey Bhide
committed
Add Get/Update methods for Properties API
1 parent 7519a6b commit 22c8b9b

File tree

3 files changed

+114
-0
lines changed

3 files changed

+114
-0
lines changed

clients/splunk/properties.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package splunk
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"io/ioutil"
7+
"net/http"
8+
"net/url"
9+
"reflect"
10+
"strings"
11+
)
12+
13+
// PropertiesService encapsulates Splunk Properties API
14+
15+
type PropertiesService struct {
16+
client *Client
17+
}
18+
19+
func newPropertiesService(client *Client) *PropertiesService {
20+
return &PropertiesService{
21+
client: client,
22+
}
23+
}
24+
25+
type Entry struct {
26+
Value string
27+
}
28+
29+
// stringResponseDecoder decodes http response string
30+
// Properties API operates on particular key in the configuration file.
31+
// CRUD for properties API returns JSON/XML encoded response for error cases and returns a string response for success
32+
type stringResponseDecoder struct{
33+
}
34+
35+
func getPropertiesUri(file string, stanza string, key string) (string) {
36+
return fmt.Sprintf("properties/%s/%s/%s", url.PathEscape(file), url.PathEscape(stanza), url.PathEscape(key))
37+
}
38+
39+
func (d stringResponseDecoder) Decode(resp *http.Response, v interface{}) error {
40+
body, err := ioutil.ReadAll(resp.Body)
41+
if err != nil {
42+
return err
43+
}
44+
if 200 <= resp.StatusCode && resp.StatusCode <= 299 {
45+
tempEntry := &Entry{
46+
Value: string(body),
47+
}
48+
vVal, tempVal := reflect.ValueOf(v), reflect.ValueOf(tempEntry)
49+
vVal.Elem().Set(tempVal.Elem())
50+
return nil
51+
}
52+
return json.Unmarshal(body, v)
53+
}
54+
55+
// UpdateKey updates value for specified key from the specified stanza in the configuration file
56+
func (p *PropertiesService) UpdateKey(file string, stanza string, key string, value string) (*string, *http.Response, error) {
57+
apiError := &APIError{}
58+
body := strings.NewReader(fmt.Sprintf("value=%s", value))
59+
resp, err := p.client.New().Post(
60+
getPropertiesUri(file, stanza, key)).Body(body).ResponseDecoder(stringResponseDecoder{}).Receive(nil, apiError)
61+
if err != nil || !apiError.Empty() {
62+
return nil, resp, relevantError(err, apiError)
63+
}
64+
return nil, resp, relevantError(err, apiError)
65+
}
66+
67+
// GetKey returns value for the given key from the specified stanza in the configuration file
68+
func (p *PropertiesService) GetKey(file string, stanza string, key string) (*string, *http.Response, error) {
69+
apiError := &APIError{}
70+
output := &Entry{}
71+
resp, err := p.client.New().Get(
72+
getPropertiesUri(file, stanza, key)).ResponseDecoder(stringResponseDecoder{}).Receive(output, apiError)
73+
if err != nil || !apiError.Empty() {
74+
return nil, resp, relevantError(err, apiError)
75+
}
76+
return &output.Value, resp, relevantError(err, apiError)
77+
}

clients/splunk/properties_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package splunk
2+
3+
import (
4+
"gotest.tools/assert"
5+
"testing"
6+
)
7+
8+
func TestPropertiesService_GetKey(t *testing.T) {
9+
propertiesSvc := TestGlobalSplunkClient(t).Properties
10+
11+
// Negative cases
12+
_, response, err := propertiesSvc.GetKey("foo", "bar", "key")
13+
assert.ErrorContains(t, err, "splunk: foo does not exist")
14+
assert.Equal(t, response.StatusCode, 404)
15+
_, response, err = propertiesSvc.GetKey("b/a/z","b-ar", "k-ey")
16+
assert.ErrorContains(t, err, "ERROR splunk: Directory traversal risk in /nobody/system/b/a/z at segment \"b/a/z\"")
17+
assert.Equal(t, response.StatusCode, 403)
18+
_, response, err = propertiesSvc.GetKey("foo-bar", "b/a/z", "k-ey")
19+
assert.ErrorContains(t, err, "splunk: foo-bar does not exist")
20+
assert.Equal(t, response.StatusCode, 404)
21+
_, response, err = propertiesSvc.UpdateKey("foo", "bar", "pass4SymmKey", "bar")
22+
assert.ErrorContains(t, err, "splunk: bar does not exist")
23+
assert.Equal(t, response.StatusCode, 404)
24+
25+
26+
_, response, err = propertiesSvc.GetKey("server", "general", "pass4SymmKey")
27+
assert.Equal(t, response.StatusCode, 200)
28+
29+
// Update value for pass4SymmKey and check if the new value is reflected
30+
_, response, err = propertiesSvc.UpdateKey("server", "general", "pass4SymmKey", "bar")
31+
assert.Equal(t, response.StatusCode, 200)
32+
currentValue, response, err := propertiesSvc.GetKey("server", "general", "pass4SymmKey")
33+
assert.Equal(t, response.StatusCode, 200)
34+
assert.Equal(t, *currentValue, "bar")
35+
}

clients/splunk/splunk.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ type API struct {
1919
client *Client
2020
Introspection *IntrospectionService
2121
AccessControl *AccessControlService
22+
Properties *PropertiesService
2223
// XXX ...
2324
}
2425

@@ -37,6 +38,7 @@ func (params *APIParams) NewAPI(ctx context.Context) *API {
3738
client: client.Path("services/"),
3839
Introspection: newIntrospectionService(client.New()),
3940
AccessControl: newAccessControlService(client.New()),
41+
Properties: newPropertiesService(client.New()),
4042
}
4143
}
4244

0 commit comments

Comments
 (0)