Skip to content

Commit 51e8e6e

Browse files
committed
Add kibana object resource.
1 parent 20c7590 commit 51e8e6e

File tree

3 files changed

+208
-3
lines changed

3 files changed

+208
-3
lines changed

README.md

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ See [the docs for more information](https://www.terraform.io/docs/plugins/basics
2020

2121
```
2222
provider "elasticsearch" {
23-
url = ""
23+
url = "https://search-foo-bar-pqrhr4w3u4dzervg41frow4mmy.us-east-1.es.amazonaws.com" # Don't include port at the end for aws
2424
aws_access_key = ""
2525
aws_secret_key = ""
2626
aws_token = "" # if necessary
@@ -49,10 +49,30 @@ resource "elasticsearch_index_template" "test" {
4949
}
5050
}
5151
52-
resource "elasticsearch_kibana_visualization" "test" {
52+
# A saved search, visualization or dashboard
53+
resource "elasticsearch_kibana_object" "test_dashboard" {
54+
body = "${file("dashboard_path.txt")}"
5355
}
5456
55-
resource "elasticsearch_kibana_dashboard" "test" {
57+
resource "elasticsearch_kibana_object" "test_visualization" {
58+
body = <<EOF
59+
[
60+
{
61+
"_id": "response-time-percentile",
62+
"_type": "visualization",
63+
"_source": {
64+
"title": "Total response time percentiles",
65+
"visState": "{\"title\":\"Total response time percentiles\",\"type\":\"line\",\"params\":{\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"showCircles\":true,\"interpolate\":\"linear\",\"scale\":\"linear\",\"drawLinesBetweenPoints\":true,\"radiusRatio\":9,\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"percentiles\",\"schema\":\"metric\",\"params\":{\"field\":\"app.total_time\",\"percents\":[50,90,95]}},{\"id\":\"2\",\"enabled\":true,\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"auto\",\"customInterval\":\"2h\",\"min_doc_count\":1,\"extended_bounds\":{}}},{\"id\":\"3\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"group\",\"params\":{\"field\":\"system.syslog.program\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"_term\"}}],\"listeners\":{}}",
66+
"uiStateJSON": "{}",
67+
"description": "",
68+
"version": 1,
69+
"kibanaSavedObjectMeta": {
70+
"searchSourceJSON": "{\"index\":\"filebeat-*\",\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[]}"
71+
}
72+
}
73+
}
74+
]
75+
EOF
5676
}
5777
```
5878

provider.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package main
22

33
import (
4+
"log"
45
"net/http"
56
"net/url"
67
"regexp"
@@ -50,6 +51,7 @@ func Provider() terraform.ResourceProvider {
5051
ResourcesMap: map[string]*schema.Resource{
5152
"elasticsearch_index_template": resourceElasticsearchIndexTemplate(),
5253
"elasticsearch_snapshot_repository": resourceElasticsearchSnapshotRepository(),
54+
"elasticsearch_kibana_object": resourceElasticsearchKibanaObject(),
5355
},
5456

5557
ConfigureFunc: providerConfigure,
@@ -68,6 +70,7 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) {
6870
}
6971

7072
if m := awsUrlRegexp.FindStringSubmatch(parsedUrl.Hostname()); m != nil {
73+
log.Printf("[INFO] Using AWS: %+v", m[1])
7174
opts = append(opts, elastic.SetHttpClient(awsHttpClient(m[1], d)), elastic.SetSniff(false))
7275
}
7376

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"context"
7+
"encoding/json"
8+
9+
"github.com/hashicorp/terraform/helper/schema"
10+
elastic "gopkg.in/olivere/elastic.v5"
11+
)
12+
13+
func resourceElasticsearchKibanaObject() *schema.Resource {
14+
return &schema.Resource{
15+
Create: resourceElasticsearchKibanaObjectCreate,
16+
Read: resourceElasticsearchKibanaObjectRead,
17+
Update: resourceElasticsearchKibanaObjectUpdate,
18+
Delete: resourceElasticsearchKibanaObjectDelete,
19+
Schema: map[string]*schema.Schema{
20+
"body": &schema.Schema{
21+
Type: schema.TypeString,
22+
Required: true,
23+
// ForceNew: true,
24+
// DiffSuppressFunc: diffSuppressKibanaObject,
25+
},
26+
"index": &schema.Schema{
27+
Type: schema.TypeString,
28+
Optional: true,
29+
Default: ".kibana",
30+
},
31+
},
32+
}
33+
}
34+
35+
func resourceElasticsearchKibanaObjectCreate(d *schema.ResourceData, meta interface{}) error {
36+
client := meta.(*elastic.Client)
37+
// Use the IndexExists service to check if a specified index exists.
38+
exists, err := client.IndexExists(d.Get("index").(string)).Do(context.TODO())
39+
if err != nil {
40+
return err
41+
}
42+
if !exists {
43+
log.Printf("[INFO] Creating new kibana index")
44+
mapping := `{
45+
"search": {
46+
"properties": {
47+
"hits": {
48+
"type": "integer",
49+
},
50+
"version": {
51+
"type": "integer",
52+
}
53+
}
54+
}
55+
}`
56+
createIndex, err := client.CreateIndex(d.Get("index").(string)+"/_mapping/search").Body(mapping).Do(context.TODO())
57+
if err != nil {
58+
log.Printf("[INFO] Failed to creating new kibana index: %+v", err)
59+
return err
60+
}
61+
if !createIndex.Acknowledged {
62+
return fmt.Errorf("fail to create the Elasticsearch index")
63+
}
64+
}
65+
66+
id, err := resourceElasticsearchPutKibanaObject(d, meta)
67+
68+
if err != nil {
69+
log.Printf("[INFO] Failed to put kibana object: %+v", err)
70+
return err
71+
}
72+
73+
d.SetId(id)
74+
log.Printf("[INFO] Object ID: %s", d.Id())
75+
76+
return nil
77+
}
78+
79+
func resourceElasticsearchKibanaObjectRead(d *schema.ResourceData, meta interface{}) error {
80+
client := meta.(*elastic.Client)
81+
// res, err := client.IndexGetTemplate(d.Id()).Do(context.TODO())
82+
bodyString := d.Get("body").(string)
83+
var body []map[string]interface{}
84+
if err := json.Unmarshal([]byte(bodyString), &body); err != nil {
85+
return err
86+
}
87+
// TODO handle multiple objects in json
88+
id := body[0]["_id"].(string)
89+
objectType := body[0]["_type"].(string)
90+
91+
// termQuery := elastic.Query(elastic.NewTermQuery("title", id))
92+
result, err := client.Get().Index(d.Get("index").(string)).Type(objectType).Id(id).Do(context.TODO())
93+
if err != nil {
94+
log.Printf("[INFO] Not found: %s %s %s", id, objectType, d.Get("index").(string))
95+
return err
96+
}
97+
if result.Found {
98+
// search.Hits.Hits.Fields
99+
// search.Hits.Hits.Source
100+
d.Set("index", d.Get("index").(string))
101+
d.Set("body", result.Source)
102+
// already exists
103+
} else {
104+
return fmt.Errorf("Object not found.")
105+
}
106+
107+
// t := res[d.Id()]
108+
// tj, err := json.Marshal(t)
109+
// if err != nil {
110+
// return err
111+
// }
112+
// d.Set("name", d.Id())
113+
// d.Set("body", string(tj))
114+
return nil
115+
}
116+
117+
func resourceElasticsearchKibanaObjectUpdate(d *schema.ResourceData, meta interface{}) error {
118+
_, err := resourceElasticsearchPutKibanaObject(d, meta)
119+
return err
120+
}
121+
122+
func resourceElasticsearchKibanaObjectDelete(d *schema.ResourceData, meta interface{}) error {
123+
client := meta.(*elastic.Client)
124+
// _, err := client.IndexDeleteTemplate(d.Id()).Do(context.TODO())
125+
126+
bodyString := d.Get("body").(string)
127+
var body []map[string]interface{}
128+
if err := json.Unmarshal([]byte(bodyString), &body); err != nil {
129+
return err
130+
}
131+
// TODO handle multiple objects in json
132+
id := body[0]["_id"].(string)
133+
objectType := body[0]["_type"].(string)
134+
135+
res, err := client.Delete().
136+
Index(d.Get("index").(string)).
137+
Type(objectType).
138+
Id(id).
139+
Do(context.TODO())
140+
141+
if err != nil {
142+
return err
143+
}
144+
if !res.Found {
145+
// fmt.Print("Document deleted from from index\n")
146+
return fmt.Errorf("failed to delete the object")
147+
}
148+
149+
return nil
150+
}
151+
152+
func resourceElasticsearchPutKibanaObject(d *schema.ResourceData, meta interface{}) (string, error) {
153+
client := meta.(*elastic.Client)
154+
// name := d.Get("name").(string)
155+
// body := d.Get("body").(string)
156+
// _, err := client.IndexPutTemplate(name).BodyString(body).Create(create).Do(context.TODO())
157+
158+
bodyString := d.Get("body").(string)
159+
var body []map[string]interface{}
160+
if err := json.Unmarshal([]byte(bodyString), &body); err != nil {
161+
log.Printf("[INFO] Failed to unmarshal: %+v", err)
162+
return "", err
163+
}
164+
// TODO handle multiple objects in json
165+
id := body[0]["_id"].(string)
166+
objectType := body[0]["_type"].(string)
167+
data := body[0]["_source"]
168+
169+
// will PUT with the given id
170+
_, err := client.Index().
171+
Index(d.Get("index").(string)).
172+
Type(objectType).
173+
Id(id).
174+
BodyJson(&data).
175+
Do(context.TODO())
176+
177+
if err != nil {
178+
return "", err
179+
}
180+
181+
return id, nil
182+
}

0 commit comments

Comments
 (0)