Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ jobs:
ports:
- 8000:8000
- 8089:8089
volumes:
- ${{ github.workspace }}:/workspace

steps:
- name: Set up Go 1.x
Expand All @@ -44,5 +46,16 @@ jobs:
- name: Build
run: go build -v .

- name: Set up Terraform 1.1.7
uses: hashicorp/setup-terraform@v3
with:
terraform_version: "1.1.7"

- name: Terraform init
run: terraform -chdir=terraform init

- name: Terraform apply
run: terraform -chdir=terraform apply --auto-approve

- name: Test
run: TF_ACC=1 SPLUNK_HOME=/opt/splunk SPLUNK_URL=localhost:8089 SPLUNK_USERNAME=admin SPLUNK_PASSWORD=password go test ./... -v
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Ignore dist file
.idea
.terraform
.terraform.lock.hcl
dist
terraform-provider-splunk
terraform.tfstate
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## 1.4.27
* Support for lookup table files

## 1.4.26
* Fix: Add retry mechanism to dashboard's acl endpoint

Expand Down
4 changes: 4 additions & 0 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ type Client struct {
host string
httpClient *http.Client
userAgent string
urlEncoded bool
}

// NewRequest creates a new HTTP Request and set proper header
Expand All @@ -60,6 +61,9 @@ func (c *Client) NewRequest(httpMethod, url string, body io.Reader) (*http.Reque
}
request.Header.Set("Accept", "application/json")
request.Header.Set("User-Agent", c.userAgent)
if c.urlEncoded {
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
}
return request, nil
}

Expand Down
30 changes: 30 additions & 0 deletions client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,36 @@ func TestNewRequestUserAgentHeader(t *testing.T) {
}
}

func TestNewRequestWithoutContentTypeHeader(t *testing.T) {
client, err := NewDefaultSplunkdClient()
if err != nil {
t.Error(err)
}
req, err := client.NewRequest(MethodGet, testURL, nil)
if err != nil {
t.Errorf("NewRequest returns unexpected error %v", err)
}
if req.Header["Content-Type"] != nil {
t.Errorf("NewRequest Content-Type is %v, want nil", req.Header["Content-Type"])
}
}

func TestNewRequestWithContentTypeHeader(t *testing.T) {
client, err := NewDefaultSplunkdClient()
if err != nil {
t.Error(err)
}
client.urlEncoded = true
req, err := client.NewRequest(MethodGet, testURL, nil)
if err != nil {
t.Errorf("NewRequest returns unexpected error %v", err)
}
expectedContentType := []string{"application/x-www-form-urlencoded"}
if got, want := req.Header["Content-Type"], expectedContentType; !reflect.DeepEqual(got, want) {
t.Errorf("NewRequest Content-Type is %v, want %v", got, want)
}
}

func TestNewRequestSessionKey(t *testing.T) {
client, err := NewDefaultSplunkdClient()
if err != nil {
Expand Down
65 changes: 65 additions & 0 deletions client/lookup_table_file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package client

import (
"fmt"
"log"
"net/http"
"net/http/httputil"
)

func (client *Client) CreateLookupTableFile(name string, owner string, app string, contents string) error {
values := []byte(fmt.Sprintf("namespace=%s&lookup_file=%s&owner=%s&contents=%s", app, name, owner, contents))
endpoint := client.BuildSplunkURL(nil, "services", "data", "lookup_edit", "lookup_contents")
client.urlEncoded = true
resp, err := client.Post(endpoint, values)
if err != nil {
return err
}

respBody, error := httputil.DumpResponse(resp, true)
if error != nil {
log.Printf("[ERROR] Error occured during CreateLookup %s", error)
}

log.Printf("[DEBUG] Response object returned from CreateLookup is: %s", string(respBody))

defer resp.Body.Close()
return nil
}

func (client *Client) ReadLookupTableFile(name, owner, app string) (*http.Response, error) {
values := []byte(fmt.Sprintf("namespace=%s&lookup_file=%s&owner=%s", app, name, owner))
client.urlEncoded = true
endpoint := client.BuildSplunkURL(nil, "services", "data", "lookup_edit", "lookup_data")
resp, err := client.Post(endpoint, values)
return resp, err
}

func (client *Client) UpdateLookupTableFile(name string, owner string, app string, contents string) error {
values := []byte(fmt.Sprintf("namespace=%s&lookup_file=%s&owner=%s&contents=%s", app, name, owner, contents))
endpoint := client.BuildSplunkURL(nil, "services", "data", "lookup_edit", "lookup_contents")
client.urlEncoded = true
resp, err := client.Post(endpoint, values)
if err != nil {
return err
}
defer resp.Body.Close()
return nil
}

func (client *Client) DeleteLookupTableFile(name string, owner string, app string) (*http.Response, error) {
endpoint := client.BuildSplunkURL(nil, "servicesNS", owner, app, "data", "lookup-table-files", name)
resp, err := client.Delete(endpoint)
if err != nil {
return nil, err
}

respBody, error := httputil.DumpResponse(resp, true)
if error != nil {
log.Printf("[ERROR] Error occured during DeleteLookup %s", error)
}

log.Printf("[DEBUG] Response object returned from DeleteLookup is: %s", string(respBody))

return resp, nil
}
8 changes: 8 additions & 0 deletions client/models/lookup_table_file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package models

type LookupTableFile struct {
App string `json:"namespace,omitempty" url:"namespace,omitempty"`
Owner string `json:"owner,omitempty" url:"owner,omitempty"`
FileName string `json:"lookup_file,omitempty" url:"lookup_file,omitempty"`
FileContents string `json:"contents,omitempty" url:"contents,omitempty"`
}
31 changes: 31 additions & 0 deletions docs/resources/lookup_table_file.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Resource: splunk_lookup_table_file
Create and manage lookup table files.

## Example Usage
```
resource "splunk_lookup_table_file" "lookup_table_file" {
app = "search"
owner = "nobody"
file_name = "lookup.csv"
file_contents = [
["status", "status_description", "status_type"],
["100", "Continue", "Informational"],
["101", "Switching Protocols", "Informational"],
["200", "OK", "Successful"]
]
}
```

## Argument Reference
For latest resource argument reference: https://docs.splunk.com/Documentation/Splunk/latest/Knowledge/LookupexampleinSplunkWeb

This resource block supports the following arguments:
* `app` - (Required) The app context for the resource.
* `owner` - (Required) User name of resource owner. Defaults to the resource creator. Required for updating any knowledge object ACL properties. nobody = All users may access the resource, but write access to the resource might be restricted.
* `file_name` - (Required) A name for the lookup table file. Generally ends with ".csv"
* `file_contents` - (Required) The column header and row value contents for the lookup table file.

## Attribute Reference
In addition to all arguments above, This resource block exports the following arguments:

* `id` - The ID of the lookup table file resource
1 change: 1 addition & 0 deletions splunk/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ func providerResources() map[string]*schema.Resource {
"splunk_inputs_tcp_cooked": inputsTCPCooked(),
"splunk_inputs_tcp_splunk_tcp_token": inputsTCPSplunkTCPToken(),
"splunk_inputs_tcp_ssl": inputsTCPSSL(),
"splunk_lookup_table_file": lookupTableFile(),
"splunk_outputs_tcp_default": outputsTCPDefault(),
"splunk_outputs_tcp_server": outputsTCPServer(),
"splunk_outputs_tcp_group": outputsTCPGroup(),
Expand Down
134 changes: 134 additions & 0 deletions splunk/resource_splunk_lookup_table_file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package splunk

import (
"encoding/json"
"errors"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/splunk/terraform-provider-splunk/client/models"
"io"
)

func lookupTableFile() *schema.Resource {
return &schema.Resource{
Schema: map[string]*schema.Schema{
"app": {
Type: schema.TypeString,
ForceNew: true,
Required: true,
Description: "The parent app to the lookup.",
},
"owner": {
Type: schema.TypeString,
ForceNew: true,
Required: true,
Description: "The owner of the lookup.",
},
"file_name": {
Type: schema.TypeString,
ForceNew: true,
Required: true,
Description: "A file name for the lookup.",
},
"file_contents": {
Type: schema.TypeList,
Required: true,
Elem: &schema.Schema{
Type: schema.TypeList,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
Description: "The contents of the lookup.",
},
},
Create: lookupTableFileCreate,
Read: lookupTableFileRead,
Update: lookupTableFileUpdate,
Delete: lookupTableFileDelete,
}
}

func lookupTableFileCreate(d *schema.ResourceData, meta interface{}) error {
provider := meta.(*SplunkProvider)
lookupTableFile := getLookupTableFile(d)

err := (*provider.Client).CreateLookupTableFile(lookupTableFile.FileName, lookupTableFile.Owner, lookupTableFile.App, lookupTableFile.FileContents)
if err != nil {
return err
}

d.SetId(lookupTableFile.FileName)
return lookupTableFileRead(d, meta)
}

func lookupTableFileRead(d *schema.ResourceData, meta interface{}) error {
provider := meta.(*SplunkProvider)
lookupTableFile := getLookupTableFile(d)

resp, err := (*provider.Client).ReadLookupTableFile(lookupTableFile.FileName, lookupTableFile.Owner, lookupTableFile.App)
if err != nil {
return err
}
defer resp.Body.Close()

bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
return err
}

var fileContents [][]string
if err := json.Unmarshal(bodyBytes, &fileContents); err != nil {
return err
}

if err = d.Set("file_contents", fileContents); err != nil {
return err
}

return nil
}

func lookupTableFileUpdate(d *schema.ResourceData, meta interface{}) error {
provider := meta.(*SplunkProvider)
lookupTableFile := getLookupTableFile(d)

err := (*provider.Client).UpdateLookupTableFile(lookupTableFile.FileName, lookupTableFile.Owner, lookupTableFile.App, lookupTableFile.FileContents)
if err != nil {
return err
}

return lookupTableFileRead(d, meta)
}

func lookupTableFileDelete(d *schema.ResourceData, meta interface{}) error {
provider := meta.(*SplunkProvider)
lookupTableFile := getLookupTableFile(d)

resp, err := (*provider.Client).DeleteLookupTableFile(lookupTableFile.FileName, lookupTableFile.Owner, lookupTableFile.App)
if err != nil {
return err
}
defer resp.Body.Close()

switch resp.StatusCode {
case 200, 201:
return nil

default:
errorResponse := &models.InputsUDPResponse{}
_ = json.NewDecoder(resp.Body).Decode(errorResponse)
err := errors.New(errorResponse.Messages[0].Text)
return err
}
}

func getLookupTableFile(d *schema.ResourceData) (lookupTableFile *models.LookupTableFile) {
fileContents, _ := json.Marshal(d.Get("file_contents"))
lookupTableFile = &models.LookupTableFile{
App: d.Get("app").(string),
Owner: d.Get("owner").(string),
FileName: d.Get("file_name").(string),
FileContents: string(fileContents),
}
return lookupTableFile
}
Loading
Loading