Skip to content

Commit e59e9b4

Browse files
authored
Merge pull request #199 from mploski/feature/add-lookup-definition-support
Add lookup definition support
2 parents b82e604 + a298449 commit e59e9b4

File tree

9 files changed

+621
-18
lines changed

9 files changed

+621
-18
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
## 1.4.28
2+
* Support for lookup definition
3+
14
## 1.4.27
25
* Support for lookup table files
36

client/acl.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@ package client
22

33
import (
44
"fmt"
5+
"log"
56
"net/http"
7+
"net/http/httputil"
68
"strings"
79

8-
"github.com/splunk/terraform-provider-splunk/client/models"
9-
1010
"github.com/google/go-querystring/query"
11+
"github.com/splunk/terraform-provider-splunk/client/models"
1112
)
1213

1314
// https://docs.splunk.com/Documentation/Splunk/8.0.4/RESTUM/RESTusing#Access_Control_List
@@ -62,11 +63,21 @@ func (client *Client) UpdateAcl(owner, app, name string, acl *models.ACLObject,
6263
resourcePath = append(resourcePath, name, "acl")
6364
endpoint := client.BuildSplunkURL(nil, resourcePath...)
6465
resp, err := client.Post(endpoint, values)
66+
requestBody, _ := httputil.DumpRequest(resp.Request, false)
6567
if err != nil {
6668
return fmt.Errorf("GET failed for endpoint %s: %s", endpoint.Path, err)
6769
}
6870

6971
defer resp.Body.Close()
72+
73+
respBody, error := httputil.DumpResponse(resp, true)
74+
if error != nil {
75+
log.Printf("[ERROR] Error occured during acl creation %s", error)
76+
}
77+
78+
log.Printf("[DEBUG] Request object coming acl is: %s and body: %s", string(requestBody), string(values.Encode()))
79+
log.Printf("[DEBUG] Response object returned from acl creation: %s", string(respBody))
80+
7081
return nil
7182
}
7283

client/lookup_definition.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package client
2+
3+
import (
4+
"log"
5+
"net/http"
6+
"net/http/httputil"
7+
8+
"github.com/google/go-querystring/query"
9+
"github.com/splunk/terraform-provider-splunk/client/models"
10+
)
11+
12+
func (client *Client) CreateLookupDefinitionObject(owner string, app string, splunkLookupDefObj *models.SplunkLookupDefinitionObject) error {
13+
values, err := query.Values(&splunkLookupDefObj)
14+
if err != nil {
15+
return err
16+
}
17+
endpoint := client.BuildSplunkURL(nil, "servicesNS", owner, app, "data", "transforms", "lookups")
18+
resp, err := client.Post(endpoint, values)
19+
if err != nil {
20+
return err
21+
}
22+
defer resp.Body.Close()
23+
24+
respBody, error := httputil.DumpResponse(resp, true)
25+
if error != nil {
26+
log.Printf("[ERROR] Error occured during CreateLookupDefinition %s", error)
27+
}
28+
29+
log.Printf("[DEBUG] Response object returned from CreateLookupDefinition is: %s", string(respBody))
30+
return nil
31+
}
32+
33+
func (client *Client) ReadLookupDefinitionObject(name, owner, app string) (*http.Response, error) {
34+
endpoint := client.BuildSplunkURL(nil, "servicesNS", owner, app, "data", "transforms", "lookups", name)
35+
resp, err := client.Get(endpoint)
36+
requestBody, _ := httputil.DumpRequest(resp.Request, true)
37+
if err != nil {
38+
log.Printf("[ERROR] Error occured during ReadLookupDefinitionObject %s", string(requestBody))
39+
return nil, err
40+
}
41+
respBody, error := httputil.DumpResponse(resp, true)
42+
if error != nil {
43+
log.Printf("[ERROR] Error occured during ReadLookupDefinitionObject %s", error)
44+
}
45+
46+
log.Printf("[DEBUG] Request object returned from ReadLookupDefinitionObject is: %s", string(requestBody))
47+
log.Printf("[DEBUG] Response object returned from ReadLookupDefinitionObject is: %s", string(respBody))
48+
49+
return resp, nil
50+
}
51+
52+
func (client *Client) UpdateLookupDefinitionObject(owner string, app string, name string, splunkLookupDefObj *models.SplunkLookupDefinitionObject) error {
53+
values, err := query.Values(&splunkLookupDefObj)
54+
values.Del("name")
55+
if err != nil {
56+
return err
57+
}
58+
endpoint := client.BuildSplunkURL(nil, "servicesNS", owner, app, "data", "transforms", "lookups", name)
59+
resp, err := client.Post(endpoint, values)
60+
if err != nil {
61+
return err
62+
}
63+
respBody, error := httputil.DumpResponse(resp, true)
64+
if error != nil {
65+
log.Printf("[ERROR] Error occured during UpdateLookupDefinitionObject %s", error)
66+
}
67+
68+
log.Printf("[DEBUG] Response object returned from UpdateLookupDefinitionObject is: %s", string(respBody))
69+
70+
defer resp.Body.Close()
71+
72+
return nil
73+
}
74+
75+
func (client *Client) DeleteLookupDefinitionObject(owner string, app string, name string) (*http.Response, error) {
76+
endpoint := client.BuildSplunkURL(nil, "servicesNS", owner, app, "data", "transforms", "lookups", name)
77+
resp, err := client.Delete(endpoint)
78+
if err != nil {
79+
return nil, err
80+
}
81+
respBody, error := httputil.DumpResponse(resp, true)
82+
if error != nil {
83+
log.Printf("[ERROR] Error occured during DeleteLookupDefinitionObject %s", error)
84+
}
85+
86+
log.Printf("[DEBUG] Response object returned from DeleteLookupDefinitionObject is: %s", string(respBody))
87+
88+
defer resp.Body.Close()
89+
90+
return resp, nil
91+
}

client/models/lookup_definition.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package models
2+
3+
type SplunkLookupDefinitionResponse struct {
4+
Entry []SplunkLookupDefinitionEntry `json:"entry"`
5+
Messages []ErrorMessage `json:"messages"`
6+
}
7+
8+
type SplunkLookupDefinitionEntry struct {
9+
Name string `json:"name"`
10+
ACL ACLObject `json:"acl"`
11+
Content SplunkLookupDefinitionObject `json:"content"`
12+
}
13+
14+
type SplunkLookupDefinitionObject struct {
15+
Name string `json:"name,omitempty" url:"name,omitempty"`
16+
Filename string `json:"filename,omitempty" url:"filename,omitempty"`
17+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
2+
# Resource: splunk_lookup_definition
3+
4+
Manage lookup definitions in Splunk. For more information on lookup definitions, refer to the official Splunk documentation: https://docs.splunk.com/Documentation/Splunk/latest/Knowledge/Aboutlookupsandfieldactions
5+
6+
## Example Usage
7+
```hcl
8+
resource "splunk_lookup_definition" "example" {
9+
name = "example_lookup_definition"
10+
filename = "example_lookup_file.csv"
11+
acl {
12+
owner = "admin"
13+
app = "search"
14+
sharing = "app"
15+
read = ["*"]
16+
write = ["admin"]
17+
}
18+
}
19+
```
20+
21+
## Argument Reference
22+
This resource block supports the following arguments:
23+
* `name` - (Required) A unique name for the lookup definition within the app context.
24+
* `filename` - (Required) The filename for the lookup table, usually ending in `.csv`.
25+
* `acl` - (Optional) Defines the access control list (ACL) for the lookup definition. See [acl.md](acl.md) for more details.
26+
27+
## Validation Rules
28+
When `acl.sharing` is set to `user`, the `acl.read` and `acl.write` fields must not be explicitly set. Setting them will trigger a validation error.
29+
30+
## Attribute Reference
31+
In addition to the arguments listed above, this resource exports the following attributes:
32+
33+
* `id` - The ID of the lookup table file resource.

splunk/acl.go

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package splunk
22

33
import (
4+
"fmt"
5+
46
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
7+
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
58
"github.com/splunk/terraform-provider-splunk/client/models"
69
)
710

@@ -29,31 +32,29 @@ func aclSchema() *schema.Schema {
2932
"nobody = All users may access the resource, but write access to the resource might be restricted.",
3033
},
3134
"sharing": {
32-
Type: schema.TypeString,
33-
Optional: true,
34-
Computed: true,
35+
Type: schema.TypeString,
36+
Optional: true,
37+
Computed: true,
38+
ValidateFunc: validation.StringInSlice([]string{"user", "app", "global"}, false),
39+
ForceNew: true,
3540
Description: "Indicates how the resource is shared. Required for updating any knowledge object ACL properties." +
3641
"app: Shared within a specific app" +
3742
"global: (Default) Shared globally to all apps." +
3843
"user: Private to a user",
3944
},
4045
"read": {
41-
Type: schema.TypeList,
42-
Optional: true,
43-
Computed: true,
44-
Elem: &schema.Schema{
45-
Type: schema.TypeString,
46-
},
46+
Type: schema.TypeList,
47+
Optional: true,
48+
Computed: true,
49+
Elem: &schema.Schema{Type: schema.TypeString},
4750
Description: "Properties that indicate resource read permissions.",
4851
},
4952
"write": {
50-
Type: schema.TypeList,
51-
Optional: true,
52-
Computed: true,
53-
Elem: &schema.Schema{
54-
Type: schema.TypeString,
55-
},
56-
Description: "Properties that indicate write permissions of the resource.",
53+
Type: schema.TypeList,
54+
Optional: true,
55+
Computed: true,
56+
Elem: &schema.Schema{Type: schema.TypeString},
57+
Description: "Properties that indicate resource write permissions.",
5758
},
5859
"can_change_perms": {
5960
Type: schema.TypeBool,
@@ -96,6 +97,37 @@ func aclSchema() *schema.Schema {
9697
}
9798
}
9899

100+
func aclValidator(diff *schema.ResourceDiff, v interface{}) error {
101+
acl := diff.Get("acl").([]interface{})
102+
if len(acl) == 0 {
103+
return nil
104+
}
105+
// Assert that each item is a map[string]interface{}
106+
aclMap, ok := acl[0].(map[string]interface{})
107+
if !ok {
108+
return fmt.Errorf("Value cannot be mapped to map!")
109+
}
110+
111+
// Check if sharing has changed to "user"
112+
if diff.HasChange("acl.0.sharing") {
113+
_, new := diff.GetChange("acl.0.sharing")
114+
if new == "user" {
115+
// Check if `read` or `write` attributes are explicitly set in the configuration, ignoring persisted state
116+
if diff.HasChange("acl.0.read") {
117+
if aclMap["read"] != nil && len(aclMap["read"].([]interface{})) > 0 {
118+
return fmt.Errorf("`acl.read` cannot be set when `acl.sharing` is `user`")
119+
}
120+
}
121+
if diff.HasChange("acl.0.write") {
122+
if aclMap["write"] != nil && len(aclMap["write"].([]interface{})) > 0 {
123+
return fmt.Errorf("`acl.write` cannot be set when `acl.sharing` is `user`")
124+
}
125+
}
126+
}
127+
}
128+
return nil
129+
}
130+
99131
func getACLConfig(r []interface{}) (acl *models.ACLObject) {
100132
acl = &models.ACLObject{}
101133
for _, v := range r {

splunk/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ func providerResources() map[string]*schema.Resource {
9191
"splunk_outputs_tcp_group": outputsTCPGroup(),
9292
"splunk_outputs_tcp_syslog": outputsTCPSyslog(),
9393
"splunk_saved_searches": savedSearches(),
94+
"splunk_lookup_definition": splunkLookupDefinitions(),
9495
"splunk_sh_indexes_manager": shIndexesManager(),
9596
"splunk_indexes": index(),
9697
"splunk_configs_conf": configsConf(),

0 commit comments

Comments
 (0)