-
Notifications
You must be signed in to change notification settings - Fork 80
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Dashboards support * Dashboard Update and Delete Support * Fix: Dashboard Entry, Dashboard Update, SplunkDashboard Object, Tests * Dashboard name suggestions * Multiline dashboard XML example * Multiline dashboard XML example - correcting quotes * Multiline dashboard XML example - correcting quotes * Correcting test without multiline XML Co-authored-by: ajayaraman <[email protected]>
- Loading branch information
Karthika
and
ajayaraman
authored
Jan 6, 2021
1 parent
f37163b
commit 1c1963e
Showing
7 changed files
with
398 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package client | ||
|
||
import ( | ||
"net/http" | ||
|
||
"github.com/splunk/terraform-provider-splunk/client/models" | ||
|
||
"github.com/google/go-querystring/query" | ||
) | ||
|
||
func (client *Client) CreateDashboardObject(owner string, app string, splunkDashboardsObj *models.SplunkDashboardsObject) error { | ||
values, err := query.Values(&splunkDashboardsObj) | ||
if err != nil { | ||
return err | ||
} | ||
endpoint := client.BuildSplunkURL(nil, "servicesNS", owner, app, "data", "ui", "views") | ||
resp, err := client.Post(endpoint, values) | ||
if err != nil { | ||
return err | ||
} | ||
defer resp.Body.Close() | ||
|
||
return nil | ||
} | ||
|
||
func (client *Client) ReadDashboardObject(name, owner, app string) (*http.Response, error) { | ||
endpoint := client.BuildSplunkURL(nil, "servicesNS", owner, app, "data", "ui", "views", name) | ||
resp, err := client.Get(endpoint) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return resp, nil | ||
} | ||
|
||
func (client *Client) UpdateDashboardObject(owner string, app string, name string, splunkDashboardsObj *models.SplunkDashboardsObject) error { | ||
values, err := query.Values(&splunkDashboardsObj) | ||
values.Del("name") | ||
if err != nil { | ||
return err | ||
} | ||
endpoint := client.BuildSplunkURL(nil, "servicesNS", owner, app, "data", "ui", "views", name) | ||
resp, err := client.Post(endpoint, values) | ||
if err != nil { | ||
return err | ||
} | ||
defer resp.Body.Close() | ||
|
||
return nil | ||
} | ||
|
||
func (client *Client) DeleteDashboardObject(owner string, app string, name string) (*http.Response, error) { | ||
endpoint := client.BuildSplunkURL(nil, "servicesNS", owner, app, "data", "ui", "views", name) | ||
resp, err := client.Delete(endpoint) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer resp.Body.Close() | ||
|
||
return resp, nil | ||
} | ||
|
||
func (client *Client) ReadAllDashboardObject() (*http.Response, error) { | ||
endpoint := client.BuildSplunkURL(nil, "servicesNS", "-", "-", "data", "ui", "views") | ||
resp, err := client.Get(endpoint) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return resp, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package models | ||
|
||
// DashboardResponse HTTP Input Response Schema | ||
type DashboardResponse struct { | ||
Entry []DashboardEntry `json:"entry"` | ||
Messages []ErrorMessage `json:"messages"` | ||
} | ||
|
||
type DashboardEntry struct { | ||
Name string `json:"name"` | ||
ACL ACLObject `json:"acl"` | ||
Content SplunkDashboardsObject `json:"content"` | ||
} | ||
|
||
type SplunkDashboardsObject struct { | ||
Name string `json:"name,omitempty" url:"name,omitempty"` | ||
EAIData string `json:"eai:data,omitempty" url:"eai:data,omitempty"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# Resource: splunk_data_ui_views | ||
Create and manage splunk dashboards/views. | ||
## Example Usage | ||
``` | ||
resource "splunk_data_ui_views" "dashboard" { | ||
name = "Terraform_Test_Dashboard" | ||
eai_data = <<EOF | ||
<dashboard> | ||
<label> | ||
Terraform Test Dashboard | ||
</label> | ||
</dashboard> | ||
EOF | ||
acl { | ||
owner = "admin" | ||
app = "search" | ||
} | ||
} | ||
``` | ||
|
||
## Argument Reference | ||
For latest resource argument reference: https://docs.splunk.com/Documentation/Splunk/8.1.1/RESTREF/RESTknowledge#data.2Fui.2Fviews | ||
|
||
This resource block supports the following arguments: | ||
* `name` - (Required) Dashboard name. | ||
* `eai:data` - (Required) Dashboard XML definition. | ||
|
||
## Attribute Reference | ||
In addition to all arguments above, This resource block exports the following arguments: | ||
|
||
* `id` - The ID of the dashboard |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
package splunk | ||
|
||
import ( | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
"net/http" | ||
"regexp" | ||
|
||
"github.com/splunk/terraform-provider-splunk/client/models" | ||
|
||
"github.com/hashicorp/terraform-plugin-sdk/helper/schema" | ||
) | ||
|
||
func splunkDashboards() *schema.Resource { | ||
return &schema.Resource{ | ||
Schema: map[string]*schema.Schema{ | ||
"name": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
Description: "Dashboard Name.", | ||
}, | ||
"eai_data": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
Description: "Dashboard XML definition.", | ||
}, | ||
"acl": aclSchema(), | ||
}, | ||
Read: splunkDashboardsRead, | ||
Create: splunkDashboardsCreate, | ||
Delete: splunkDashboardsDelete, | ||
Update: splunkDashboardsUpdate, | ||
Importer: &schema.ResourceImporter{ | ||
State: schema.ImportStatePassthrough, | ||
}, | ||
} | ||
} | ||
|
||
// Functions | ||
func splunkDashboardsCreate(d *schema.ResourceData, meta interface{}) error { | ||
provider := meta.(*SplunkProvider) | ||
name := d.Get("name").(string) | ||
splunkDashboardsObj := getSplunkDashboardsConfig(d) | ||
aclObject := &models.ACLObject{} | ||
if r, ok := d.GetOk("acl"); ok { | ||
aclObject = getACLConfig(r.([]interface{})) | ||
} else { | ||
aclObject.App = "search" | ||
aclObject.Owner = "admin" | ||
aclObject.Sharing = "user" | ||
} | ||
err := (*provider.Client).CreateDashboardObject(aclObject.Owner, aclObject.App, splunkDashboardsObj) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if _, ok := d.GetOk("acl"); ok { | ||
aclObject.Sharing = "user" // hard-coding to avoid to user input; because changing object sharing permissions messes deletion of object | ||
err = (*provider.Client).UpdateAcl(aclObject.Owner, aclObject.App, name, aclObject, "data", "ui", "views") | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
|
||
d.SetId(name) | ||
return splunkDashboardsRead(d, meta) | ||
} | ||
|
||
func splunkDashboardsRead(d *schema.ResourceData, meta interface{}) error { | ||
provider := meta.(*SplunkProvider) | ||
name := d.Id() | ||
resp, err := (*provider.Client).ReadAllDashboardObject() | ||
if err != nil { | ||
return err | ||
} | ||
defer resp.Body.Close() | ||
|
||
entry, err := getDashboardByName(name, resp) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if entry == nil { | ||
return fmt.Errorf("Unable to find resource: %v", name) | ||
} | ||
|
||
resp, err = (*provider.Client).ReadDashboardObject(name, entry.ACL.Owner, entry.ACL.App) | ||
if err != nil { | ||
return err | ||
} | ||
defer resp.Body.Close() | ||
|
||
entry, err = getDashboardByName(name, resp) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if entry == nil { | ||
return fmt.Errorf("Unable to find resource: %v", name) | ||
} | ||
|
||
if err = d.Set("name", entry.Name); err != nil { | ||
return err | ||
} | ||
|
||
if err = d.Set("eai_data", entry.Content.EAIData); err != nil { | ||
return err | ||
} | ||
|
||
err = d.Set("acl", flattenACL(&entry.ACL)) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func splunkDashboardsUpdate(d *schema.ResourceData, meta interface{}) error { | ||
provider := meta.(*SplunkProvider) | ||
name := d.Get("name").(string) | ||
splunkDashboardsObj := getSplunkDashboardsConfig(d) | ||
aclObject := getACLConfig(d.Get("acl").([]interface{})) | ||
err := (*provider.Client).UpdateDashboardObject(aclObject.Owner, aclObject.App, name, splunkDashboardsObj) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
//ACL update | ||
if _, ok := d.GetOk("acl"); ok { | ||
aclObject.Sharing = "user" // hard-coding to avoid to user input; because changing object sharing permissions messes deletion of object | ||
err = (*provider.Client).UpdateAcl(aclObject.Owner, aclObject.App, name, aclObject, "data", "ui", "views") | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
|
||
return splunkDashboardsRead(d, meta) | ||
} | ||
|
||
func splunkDashboardsDelete(d *schema.ResourceData, meta interface{}) error { | ||
provider := meta.(*SplunkProvider) | ||
name := d.Id() | ||
aclObject := getACLConfig(d.Get("acl").([]interface{})) | ||
resp, err := (*provider.Client).DeleteDashboardObject(aclObject.Owner, aclObject.App, name) | ||
if err != nil { | ||
return err | ||
} | ||
defer resp.Body.Close() | ||
|
||
switch resp.StatusCode { | ||
case 200, 201: | ||
return nil | ||
|
||
default: | ||
errorResponse := &models.DashboardResponse{} | ||
_ = json.NewDecoder(resp.Body).Decode(errorResponse) | ||
err := errors.New(errorResponse.Messages[0].Text) | ||
return err | ||
} | ||
} | ||
|
||
// Helpers | ||
func getSplunkDashboardsConfig(d *schema.ResourceData) (splunkDashboardsObject *models.SplunkDashboardsObject) { | ||
splunkDashboardsObject = &models.SplunkDashboardsObject{} | ||
splunkDashboardsObject.Name = d.Get("name").(string) | ||
splunkDashboardsObject.EAIData = d.Get("eai_data").(string) | ||
return splunkDashboardsObject | ||
} | ||
|
||
func getDashboardByName(name string, httpResponse *http.Response) (dashboardEntry *models.DashboardEntry, err error) { | ||
response := &models.DashboardResponse{} | ||
switch httpResponse.StatusCode { | ||
case 200, 201: | ||
|
||
decoder := json.NewDecoder(httpResponse.Body) | ||
err := decoder.Decode(response) | ||
if err != nil { | ||
return nil, err | ||
} | ||
re := regexp.MustCompile(`(.*)`) | ||
for _, entry := range response.Entry { | ||
if name == re.FindStringSubmatch(entry.Name)[1] { | ||
return &entry, nil | ||
} | ||
} | ||
|
||
default: | ||
_ = json.NewDecoder(httpResponse.Body).Decode(response) | ||
err := errors.New(response.Messages[0].Text) | ||
return dashboardEntry, err | ||
} | ||
|
||
return dashboardEntry, nil | ||
} |
Oops, something went wrong.