Skip to content

Commit 5806186

Browse files
k3v142Serhii Okhrimenkok3v142
authored
Add script resource (#264)
Co-authored-by: Serhii Okhrimenko <[email protected]> Co-authored-by: k3v142 <[email protected]>
1 parent 7b976cd commit 5806186

File tree

4 files changed

+360
-0
lines changed

4 files changed

+360
-0
lines changed

docs/resources/script.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
---
2+
layout: "elasticsearch"
3+
page_title: "Elasticsearch: elasticsearch_script"
4+
subcategory: "Elasticsearch Opensource"
5+
description: |-
6+
Provides an Elasticsearch Opensource script resource.
7+
---
8+
9+
# elasticsearch_script
10+
11+
Provides an Elasticsearch script resource.
12+
13+
## Example Usage
14+
15+
```tf
16+
# Create a script
17+
resource "elasticsearch_script" "test_script" {
18+
script_id = "my_script"
19+
lang = "painless"
20+
source = "Math.log(_score * 2) + params.my_modifier"
21+
}
22+
```
23+
24+
## Argument Reference
25+
26+
The following arguments are supported:
27+
28+
* `script_id` - (Required) The name of the script.
29+
* `lang` - Specifies the language the script is written in. Defaults to painless..
30+
* `source` - (Required) The source of the stored script.
31+
32+
## Attributes Reference
33+
34+
The following attributes are exported:
35+
36+
* `id` - The name of the script.

es/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ func Provider() *schema.Provider {
247247
"elasticsearch_xpack_snapshot_lifecycle_policy": resourceElasticsearchXpackSnapshotLifecyclePolicy(),
248248
"elasticsearch_xpack_user": resourceElasticsearchXpackUser(),
249249
"elasticsearch_xpack_watch": resourceElasticsearchXpackWatch(),
250+
"elasticsearch_script": resourceElasticsearchScript(),
250251
},
251252

252253
DataSourcesMap: map[string]*schema.Resource{
Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
package es
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"errors"
7+
"fmt"
8+
"log"
9+
10+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
11+
12+
elastic7 "github.com/olivere/elastic/v7"
13+
elastic6 "gopkg.in/olivere/elastic.v6"
14+
)
15+
16+
var scriptSchema = map[string]*schema.Schema{
17+
"script_id": {
18+
Type: schema.TypeString,
19+
Description: "Identifier for the stored script. Must be unique within the cluster.",
20+
Required: true,
21+
ForceNew: true,
22+
},
23+
"source": {
24+
Type: schema.TypeString,
25+
Description: "The source of the stored script",
26+
Required: true,
27+
},
28+
"lang": {
29+
Type: schema.TypeString,
30+
Description: "Specifies the language the script is written in. Defaults to painless.",
31+
Default: "painless",
32+
Optional: true,
33+
},
34+
}
35+
36+
func resourceElasticsearchScript() *schema.Resource {
37+
return &schema.Resource{
38+
Create: resourceElasticsearchScriptCreate,
39+
Read: resourceElasticsearchScriptRead,
40+
Update: resourceElasticsearchScriptUpdate,
41+
Delete: resourceElasticsearchScriptDelete,
42+
Schema: scriptSchema,
43+
Importer: &schema.ResourceImporter{
44+
StateContext: schema.ImportStatePassthroughContext,
45+
},
46+
}
47+
}
48+
49+
func buildScriptJSONBody(d *schema.ResourceData) (string, error) {
50+
var err error
51+
52+
body := make(map[string]interface{})
53+
script := ScriptBody{
54+
Language: d.Get("lang").(string),
55+
Source: d.Get("source").(string),
56+
}
57+
body["script"] = script
58+
59+
data, err := json.Marshal(body)
60+
if err != nil {
61+
return "", err
62+
}
63+
64+
return string(data), nil
65+
}
66+
67+
func resourceElasticsearchScriptCreate(d *schema.ResourceData, m interface{}) error {
68+
// Determine whether the script already exists, otherwise the API will
69+
// override an existing script with the name.
70+
scriptID := d.Get("script_id").(string)
71+
_, err := resourceElasticsearchGetScript(scriptID, m)
72+
73+
if err == nil {
74+
log.Printf("[INFO] script exists: %+v", err)
75+
return fmt.Errorf("script already exists with ID: %v", scriptID)
76+
} else if err != nil && !elastic6.IsNotFound(err) && !elastic7.IsNotFound(err) {
77+
return err
78+
}
79+
80+
scriptID, err = resourceElasticsearchPutScript(d, m)
81+
82+
if err != nil {
83+
log.Printf("[INFO] Failed to put script: %+v", err)
84+
return err
85+
}
86+
87+
d.SetId(scriptID)
88+
log.Printf("[INFO] Object ID: %s", d.Id())
89+
90+
return resourceElasticsearchScriptRead(d, m)
91+
}
92+
93+
func resourceElasticsearchScriptRead(d *schema.ResourceData, m interface{}) error {
94+
scriptBody, err := resourceElasticsearchGetScript(d.Id(), m)
95+
96+
if elastic6.IsNotFound(err) || elastic7.IsNotFound(err) {
97+
log.Printf("[WARN] Script (%s) not found, removing from state", d.Id())
98+
d.SetId("")
99+
return nil
100+
}
101+
102+
if err != nil {
103+
return err
104+
}
105+
106+
ds := &resourceDataSetter{d: d}
107+
ds.set("script_id", d.Id())
108+
ds.set("source", scriptBody.Source)
109+
ds.set("lang", scriptBody.Language)
110+
111+
return ds.err
112+
}
113+
114+
func resourceElasticsearchScriptUpdate(d *schema.ResourceData, m interface{}) error {
115+
_, err := resourceElasticsearchPutScript(d, m)
116+
117+
if err != nil {
118+
return err
119+
}
120+
121+
return resourceElasticsearchScriptRead(d, m)
122+
}
123+
124+
func resourceElasticsearchScriptDelete(d *schema.ResourceData, m interface{}) error {
125+
var err error
126+
esClient, err := getClient(m.(*ProviderConf))
127+
if err != nil {
128+
return err
129+
}
130+
switch client := esClient.(type) {
131+
case *elastic7.Client:
132+
_, err = client.DeleteScript().Id(d.Id()).Do(context.TODO())
133+
case *elastic6.Client:
134+
_, err = client.DeleteScript().Id(d.Id()).Do(context.TODO())
135+
default:
136+
err = errors.New("script resource not implemented prior to Elastic v6")
137+
}
138+
139+
return err
140+
}
141+
142+
func resourceElasticsearchGetScript(scriptID string, m interface{}) (ScriptBody, error) {
143+
var scriptBody json.RawMessage
144+
var err error
145+
esClient, err := getClient(m.(*ProviderConf))
146+
if err != nil {
147+
return ScriptBody{}, err
148+
}
149+
switch client := esClient.(type) {
150+
case *elastic7.Client:
151+
var res *elastic7.GetScriptResponse
152+
res, err = client.GetScript().Id(scriptID).Do(context.TODO())
153+
if err != nil {
154+
return ScriptBody{}, err
155+
}
156+
scriptBody = res.Script
157+
case *elastic6.Client:
158+
var res *elastic6.GetScriptResponse
159+
res, err = client.GetScript().Id(scriptID).Do(context.TODO())
160+
if err != nil {
161+
return ScriptBody{}, err
162+
}
163+
scriptBody = res.Script
164+
default:
165+
err = errors.New("script resource not implemented prior to Elastic v6")
166+
}
167+
168+
var script ScriptBody
169+
170+
if err := json.Unmarshal(scriptBody, &script); err != nil {
171+
return ScriptBody{}, fmt.Errorf("error unmarshalling destination body: %+v: %+v", err, scriptBody)
172+
}
173+
174+
return script, err
175+
}
176+
177+
func resourceElasticsearchPutScript(d *schema.ResourceData, m interface{}) (string, error) {
178+
var err error
179+
scriptID := d.Get("script_id").(string)
180+
scriptBody, err := buildScriptJSONBody(d)
181+
182+
if err != nil {
183+
return "", err
184+
}
185+
186+
esClient, err := getClient(m.(*ProviderConf))
187+
if err != nil {
188+
return "", err
189+
}
190+
switch client := esClient.(type) {
191+
case *elastic7.Client:
192+
_, err = client.PutScript().
193+
Id(scriptID).
194+
BodyJson(scriptBody).
195+
Do(context.TODO())
196+
case *elastic6.Client:
197+
_, err = client.PutScript().
198+
Id(scriptID).
199+
BodyJson(scriptBody).
200+
Do(context.TODO())
201+
default:
202+
err = errors.New("script resource not implemented prior to Elastic v6")
203+
}
204+
205+
if err != nil {
206+
return "", err
207+
}
208+
209+
return scriptID, nil
210+
}
211+
212+
type ScriptBody struct {
213+
Language string `json:"lang"`
214+
Source string `json:"source"`
215+
}
216+
217+
type Script struct {
218+
Name string `json:"name"`
219+
Script ScriptBody `json:"script"`
220+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package es
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"testing"
7+
8+
elastic7 "github.com/olivere/elastic/v7"
9+
elastic6 "gopkg.in/olivere/elastic.v6"
10+
11+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
12+
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
13+
)
14+
15+
func TestAccElasticsearchScript(t *testing.T) {
16+
resource.ParallelTest(t, resource.TestCase{
17+
PreCheck: func() {
18+
testAccPreCheck(t)
19+
},
20+
Providers: testAccProviders,
21+
CheckDestroy: testCheckElasticsearchScriptDestroy,
22+
Steps: []resource.TestStep{
23+
{
24+
Config: testAccElasticsearchScript,
25+
Check: resource.ComposeTestCheckFunc(
26+
testCheckElasticsearchScriptExists("elasticsearch_script.test_script"),
27+
),
28+
},
29+
},
30+
})
31+
}
32+
33+
func testCheckElasticsearchScriptExists(name string) resource.TestCheckFunc {
34+
return func(s *terraform.State) error {
35+
rs, ok := s.RootModule().Resources[name]
36+
if !ok {
37+
return fmt.Errorf("Not found: %s", name)
38+
}
39+
if rs.Primary.ID == "" {
40+
return fmt.Errorf("No script ID is set")
41+
}
42+
43+
meta := testAccProvider.Meta()
44+
45+
var err error
46+
esClient, err := getClient(meta.(*ProviderConf))
47+
if err != nil {
48+
return err
49+
}
50+
switch client := esClient.(type) {
51+
case *elastic7.Client:
52+
_, err = client.GetScript().Id("my_script").Do(context.TODO())
53+
case *elastic6.Client:
54+
_, err = client.GetScript().Id("my_script").Do(context.TODO())
55+
default:
56+
}
57+
58+
if err != nil {
59+
return err
60+
}
61+
62+
return nil
63+
}
64+
}
65+
66+
func testCheckElasticsearchScriptDestroy(s *terraform.State) error {
67+
for _, rs := range s.RootModule().Resources {
68+
if rs.Type != "elasticsearch_script" {
69+
continue
70+
}
71+
72+
meta := testAccProvider.Meta()
73+
74+
var err error
75+
esClient, err := getClient(meta.(*ProviderConf))
76+
if err != nil {
77+
return err
78+
}
79+
switch client := esClient.(type) {
80+
case *elastic7.Client:
81+
_, err = client.GetScript().Id("my_script").Do(context.TODO())
82+
case *elastic6.Client:
83+
_, err = client.GetScript().Id("my_script").Do(context.TODO())
84+
default:
85+
}
86+
87+
if err != nil {
88+
return nil // should be not found error
89+
}
90+
91+
return fmt.Errorf("Script %q still exists", rs.Primary.ID)
92+
}
93+
94+
return nil
95+
}
96+
97+
var testAccElasticsearchScript = `
98+
resource "elasticsearch_script" "test_script" {
99+
script_id = "my_script"
100+
lang = "painless"
101+
source = "Math.log(_score * 2) + params.my_modifier"
102+
}
103+
`

0 commit comments

Comments
 (0)