-
Notifications
You must be signed in to change notification settings - Fork 94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add script resource #173
Add script resource #173
Changes from all commits
c76a508
d027f42
f21d27b
3633a63
3c1c0f6
77fa79f
50b83bd
5bde0d4
b5327c1
24a6461
f62fd11
7d16960
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
--- | ||
subcategory: "Cluster" | ||
layout: "" | ||
page_title: "Elasticstack: elasticstack_elasticsearch_script Resource" | ||
description: |- | ||
Creates or updates a stored script or search template. | ||
--- | ||
|
||
# Resource: elasticstack_elasticsearch_script | ||
|
||
Creates or updates a stored script or search template. See https://www.elastic.co/guide/en/elasticsearch/reference/current/create-stored-script-api.html | ||
|
||
## Example Usage | ||
|
||
```terraform | ||
provider "elasticstack" { | ||
elasticsearch {} | ||
} | ||
|
||
resource "elasticstack_elasticsearch_script" "my_script" { | ||
script_id = "my_script" | ||
lang = "painless" | ||
source = "Math.log(_score * 2) + params['my_modifier']" | ||
context = "score" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This example is no longer valid, and needs There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh good catch, fixed🙏 |
||
} | ||
|
||
resource "elasticstack_elasticsearch_script" "my_search_template" { | ||
script_id = "my_search_template" | ||
lang = "mustache" | ||
source = jsonencode({ | ||
query = { | ||
match = { | ||
message = "{{query_string}}" | ||
} | ||
} | ||
from = "{{from}}" | ||
size = "{{size}}" | ||
}) | ||
params = jsonencode({ | ||
query_string = "My query string" | ||
}) | ||
} | ||
``` | ||
|
||
<!-- schema generated by tfplugindocs --> | ||
## Schema | ||
|
||
### Required | ||
|
||
- `lang` (String) Script language. For search templates, use `mustache`. | ||
- `script_id` (String) Identifier for the stored script. Must be unique within the cluster. | ||
- `source` (String) For scripts, a string containing the script. For search templates, an object containing the search template. | ||
|
||
### Optional | ||
|
||
- `context` (String) Context in which the script or search template should run. | ||
- `elasticsearch_connection` (Block List, Max: 1) Used to establish connection to Elasticsearch server. Overrides environment variables if present. (see [below for nested schema](#nestedblock--elasticsearch_connection)) | ||
- `params` (String) Parameters for the script or search template. | ||
|
||
### Read-Only | ||
|
||
- `id` (String) The ID of this resource. | ||
|
||
<a id="nestedblock--elasticsearch_connection"></a> | ||
### Nested Schema for `elasticsearch_connection` | ||
|
||
Optional: | ||
|
||
- `api_key` (String, Sensitive) API Key to use for authentication to Elasticsearch | ||
- `ca_data` (String) PEM-encoded custom Certificate Authority certificate | ||
- `ca_file` (String) Path to a custom Certificate Authority certificate | ||
- `endpoints` (List of String, Sensitive) A list of endpoints the Terraform provider will point to. They must include the http(s) schema and port number. | ||
- `insecure` (Boolean) Disable TLS certificate validation | ||
- `password` (String, Sensitive) A password to use for API authentication to Elasticsearch. | ||
- `username` (String) A username to use for API authentication to Elasticsearch. | ||
|
||
## Import | ||
|
||
Import is supported using the following syntax: | ||
|
||
```shell | ||
terraform import elasticstack_elasticsearch_script.my_script <cluster_uuid>/<script id> | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
terraform import elasticstack_elasticsearch_script.my_script <cluster_uuid>/<script id> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
provider "elasticstack" { | ||
elasticsearch {} | ||
} | ||
|
||
resource "elasticstack_elasticsearch_script" "my_script" { | ||
script_id = "my_script" | ||
lang = "painless" | ||
source = "Math.log(_score * 2) + params['my_modifier']" | ||
context = "score" | ||
} | ||
|
||
resource "elasticstack_elasticsearch_script" "my_search_template" { | ||
script_id = "my_search_template" | ||
lang = "mustache" | ||
source = jsonencode({ | ||
query = { | ||
match = { | ||
message = "{{query_string}}" | ||
} | ||
} | ||
from = "{{from}}" | ||
size = "{{size}}" | ||
}) | ||
params = jsonencode({ | ||
query_string = "My query string" | ||
}) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
package cluster | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
|
||
"github.com/elastic/terraform-provider-elasticstack/internal/clients" | ||
"github.com/elastic/terraform-provider-elasticstack/internal/models" | ||
"github.com/elastic/terraform-provider-elasticstack/internal/utils" | ||
"github.com/hashicorp/terraform-plugin-log/tflog" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" | ||
) | ||
|
||
func ResourceScript() *schema.Resource { | ||
scriptSchema := map[string]*schema.Schema{ | ||
"script_id": { | ||
Description: "Identifier for the stored script. Must be unique within the cluster.", | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
}, | ||
"lang": { | ||
Description: "Script language. For search templates, use `mustache`.", | ||
Type: schema.TypeString, | ||
Required: true, | ||
ValidateFunc: validation.StringInSlice([]string{"painless", "expression", "mustache", "java"}, false), | ||
}, | ||
"source": { | ||
Description: "For scripts, a string containing the script. For search templates, an object containing the search template.", | ||
Type: schema.TypeString, | ||
Required: true, | ||
}, | ||
"params": { | ||
Description: "Parameters for the script or search template.", | ||
Type: schema.TypeString, | ||
Optional: true, | ||
DiffSuppressFunc: utils.DiffJsonSuppress, | ||
ValidateFunc: validation.StringIsJSON, | ||
}, | ||
"context": { | ||
Description: "Context in which the script or search template should run.", | ||
Type: schema.TypeString, | ||
Optional: true, | ||
}, | ||
} | ||
utils.AddConnectionSchema(scriptSchema) | ||
|
||
return &schema.Resource{ | ||
Description: "Creates or updates a stored script or search template. See https://www.elastic.co/guide/en/elasticsearch/reference/current/create-stored-script-api.html", | ||
|
||
CreateContext: resourceScriptPut, | ||
UpdateContext: resourceScriptPut, | ||
ReadContext: resourceScriptRead, | ||
DeleteContext: resourceScriptDelete, | ||
|
||
Importer: &schema.ResourceImporter{ | ||
StateContext: schema.ImportStatePassthroughContext, | ||
}, | ||
|
||
Schema: scriptSchema, | ||
} | ||
} | ||
|
||
func resourceScriptRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
var diags diag.Diagnostics | ||
client, err := clients.NewApiClient(d, meta) | ||
if err != nil { | ||
return diag.FromErr(err) | ||
} | ||
|
||
id := d.Id() | ||
compId, diags := clients.CompositeIdFromStr(id) | ||
if diags.HasError() { | ||
return diags | ||
} | ||
|
||
script, diags := client.GetElasticsearchScript(ctx, compId.ResourceId) | ||
if script == nil && diags == nil { | ||
tflog.Warn(ctx, fmt.Sprintf(`Script "%s" not found, removing from state`, compId.ResourceId)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It doesn't look like we log a message in this case for the other resources. Any reason this should be a warning? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, the reason is to let the user know that the resource is removed from state when actually not found on API which is sometimes unexpected for users. It it makes sense, I'll add it to the other resources too with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just realized that adding |
||
d.SetId("") | ||
} | ||
if diags.HasError() { | ||
return diags | ||
} | ||
|
||
if err := d.Set("script_id", compId.ResourceId); err != nil { | ||
return diag.FromErr(err) | ||
} | ||
if err := d.Set("lang", script.Language); err != nil { | ||
return diag.FromErr(err) | ||
} | ||
if err := d.Set("source", script.Source); err != nil { | ||
return diag.FromErr(err) | ||
} | ||
|
||
return diags | ||
} | ||
|
||
func resourceScriptPut(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
client, err := clients.NewApiClient(d, meta) | ||
if err != nil { | ||
return diag.FromErr(err) | ||
} | ||
|
||
scriptID := d.Get("script_id").(string) | ||
id, diags := client.ID(ctx, scriptID) | ||
if diags.HasError() { | ||
return diags | ||
} | ||
|
||
script := models.Script{ | ||
ID: scriptID, | ||
Language: d.Get("lang").(string), | ||
Source: d.Get("source").(string), | ||
} | ||
if paramsJSON, ok := d.GetOk("params"); ok { | ||
var params map[string]interface{} | ||
bytes := []byte(paramsJSON.(string)) | ||
err = json.Unmarshal(bytes, ¶ms) | ||
if err != nil { | ||
return diag.FromErr(err) | ||
} | ||
script.Params = params | ||
} | ||
if scriptContext, ok := d.GetOk("context"); ok { | ||
script.Context = scriptContext.(string) | ||
} | ||
if diags := client.PutElasticsearchScript(ctx, &script); diags.HasError() { | ||
return diags | ||
} | ||
|
||
d.SetId(id.String()) | ||
return resourceScriptRead(ctx, d, meta) | ||
} | ||
|
||
func resourceScriptDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
client, err := clients.NewApiClient(d, meta) | ||
if err != nil { | ||
return diag.FromErr(err) | ||
} | ||
|
||
compId, diags := clients.CompositeIdFromStr(d.Id()) | ||
if diags.HasError() { | ||
return diags | ||
} | ||
return client.DeleteElasticsearchScript(ctx, compId.ResourceId) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should have said this earlier sorry, having a search template example would be nice too.