Skip to content
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 support for ElasticSearch 7.8+ Index templates #120

Merged
merged 13 commits into from
Dec 15, 2020
Merged
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ env:
jobs:
- ES_VERSION=5.6.16 ES_OSS_IMAGE=elasticsearch:${ES_VERSION} ES_IMAGE=docker.elastic.co/elasticsearch/elasticsearch:${ES_VERSION} ES_COMMAND="elasticsearch -Epath.repo=/tmp"
- ES_VERSION=6.8.9 ES_OSS_IMAGE=docker.elastic.co/elasticsearch/elasticsearch-oss:${ES_VERSION} ES_IMAGE=docker.elastic.co/elasticsearch/elasticsearch:${ES_VERSION} ES_OPENDISTRO_IMAGE=amazon/opendistro-for-elasticsearch:0.9.0
- ES_VERSION=7.6.1 ES_OSS_IMAGE=docker.elastic.co/elasticsearch/elasticsearch-oss:${ES_VERSION} ES_IMAGE=docker.elastic.co/elasticsearch/elasticsearch:${ES_VERSION} ES_OPENDISTRO_IMAGE=amazon/opendistro-for-elasticsearch:1.6.0
- ES_VERSION=7.9.3 ES_OSS_IMAGE=docker.elastic.co/elasticsearch/elasticsearch-oss:${ES_VERSION} ES_IMAGE=docker.elastic.co/elasticsearch/elasticsearch:${ES_VERSION} ES_OPENDISTRO_IMAGE=amazon/opendistro-for-elasticsearch:1.6.0
addons:
ssh_known_hosts: github.com
apt:
Expand Down
63 changes: 63 additions & 0 deletions docs/resources/composable_index_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
---
layout: "elasticsearch"
page_title: "Elasticsearch: elasticsearch_composable_index_template"
subcategory: "Elasticsearch Opensource"
description: |-
Provides an Elasticsearch Composable index template resource.
---

# elasticsearch_composable_index_template

Provides an Elasticsearch Composable index template resource. This resource uses the `/_index_template`
endpoint of Elasticsearch API that is available since version 7.8. Use `elasticsearch_index_template` if
you are using older versions of Elasticsearch or if you want to keep using legacy Index Templates in Elasticsearch 7.8+.

## Example Usage

```tf
# Create an index template
resource "elasticsearch_composable_index_template" "template_1" {
name = "template_1"
body = <<EOF
{
"index_patterns": ["te*", "bar*"],
"template": {
"settings": {
"index": {
phillbaker marked this conversation as resolved.
Show resolved Hide resolved
"number_of_shards": 1
}
},
"mappings": {
"properties": {
"host_name": {
"type": "keyword"
},
"created_at": {
"type": "date",
"format": "EEE MMM dd HH:mm:ss Z yyyy"
}
}
},
"aliases": {
"mydata": { }
}
},
"priority": 200,
"version": 3
}
EOF
}
```

## Argument Reference

The following arguments are supported:

* `name` - (Required) The name of the index template.
* `body` - (Required) The JSON body of the index template.

## Attributes Reference

The following attributes are exported:

* `id` - The name of the index template.
24 changes: 24 additions & 0 deletions es/diff_suppress_funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,30 @@ func diffSuppressIndexTemplate(k, old, new string, d *schema.ResourceData) bool
return reflect.DeepEqual(oo, no)
}

/*
diffSuppressComposableIndexTemplate compares an index_template (ES >= 7.8) Index template definition
For legacy index templates (ES < 7.8) or /_template endpoint on ES >= 7.8 see diffSuppressIndexTemplate.
*/
func diffSuppressComposableIndexTemplate(k, old, new string, d *schema.ResourceData) bool {
var oo, no interface{}
if err := json.Unmarshal([]byte(old), &oo); err != nil {
return false
}
if err := json.Unmarshal([]byte(new), &no); err != nil {
return false
}

if om, ok := oo.(map[string]interface{}); ok {
normalizeComposableIndexTemplate(om)
}

if nm, ok := no.(map[string]interface{}); ok {
normalizeComposableIndexTemplate(nm)
}

return reflect.DeepEqual(oo, no)
}

func diffSuppressDestination(k, old, new string, d *schema.ResourceData) bool {
var oo, no interface{}
if err := json.Unmarshal([]byte(old), &oo); err != nil {
Expand Down
1 change: 1 addition & 0 deletions es/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ func Provider() terraform.ResourceProvider {
"elasticsearch_index": resourceElasticsearchIndex(),
"elasticsearch_index_lifecycle_policy": resourceElasticsearchDeprecatedIndexLifecyclePolicy(),
"elasticsearch_index_template": resourceElasticsearchIndexTemplate(),
"elasticsearch_composable_index_template": resourceElasticsearchComposableIndexTemplate(),
"elasticsearch_ingest_pipeline": resourceElasticsearchIngestPipeline(),
"elasticsearch_kibana_object": resourceElasticsearchKibanaObject(),
"elasticsearch_monitor": resourceElasticsearchDeprecatedMonitor(),
Expand Down
153 changes: 153 additions & 0 deletions es/resource_elasticsearch_composable_index_template.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package es

import (
"context"
"encoding/json"
"fmt"
"log"

"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
elastic7 "github.com/olivere/elastic/v7"
elastic5 "gopkg.in/olivere/elastic.v5"
elastic6 "gopkg.in/olivere/elastic.v6"
)

func resourceElasticsearchComposableIndexTemplate() *schema.Resource {
return &schema.Resource{
Create: resourceElasticsearchComposableIndexTemplateCreate,
Read: resourceElasticsearchComposableIndexTemplateRead,
Update: resourceElasticsearchComposableIndexTemplateUpdate,
Delete: resourceElasticsearchComposableIndexTemplateDelete,
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
ForceNew: true,
Required: true,
},
"body": {
Type: schema.TypeString,
Required: true,
DiffSuppressFunc: diffSuppressComposableIndexTemplate,
ValidateFunc: validation.StringIsJSON,
},
},
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
}
}

func resourceElasticsearchComposableIndexTemplateCreate(d *schema.ResourceData, meta interface{}) error {
err := resourceElasticsearchPutComposableIndexTemplate(d, meta, true)
if err != nil {
return err
}
d.SetId(d.Get("name").(string))
return nil
}

func resourceElasticsearchComposableIndexTemplateRead(d *schema.ResourceData, meta interface{}) error {
id := d.Id()

var result, version string
var err error
switch client := meta.(type) {
case *elastic7.Client:
version, err = elastic7GetVersion(client)
if err == nil {
if version < "7.8.0" {
err = fmt.Errorf("index_template endpoint only available from ElasticSearch >= 7.8, got version %s", version)
} else {
result, err = elastic7GetIndexTemplate(client, id)
}
}
default:
err = fmt.Errorf("index_template endpoint only available from ElasticSearch >= 7.8, got version < 7.0.0")
}
if err != nil {
if elastic7.IsNotFound(err) || elastic6.IsNotFound(err) || elastic5.IsNotFound(err) {
phillbaker marked this conversation as resolved.
Show resolved Hide resolved
log.Printf("[WARN] Index template (%s) not found, removing from state", id)
d.SetId("")
return nil
}

return err
}

ds := &resourceDataSetter{d: d}
ds.set("name", d.Id())
ds.set("body", result)
return ds.err
}

func elastic7GetIndexTemplate(client *elastic7.Client, id string) (string, error) {
res, err := client.IndexGetIndexTemplate(id).Do(context.TODO())
if err != nil {
return "", err
}

// No more than 1 element is expected, if the index template is not found, previous call should
// return a 404 error
t := res.IndexTemplates[0].IndexTemplate
tj, err := json.Marshal(t)
if err != nil {
return "", err
}
return string(tj), nil
}

func resourceElasticsearchComposableIndexTemplateUpdate(d *schema.ResourceData, meta interface{}) error {
return resourceElasticsearchPutComposableIndexTemplate(d, meta, false)
}

func resourceElasticsearchComposableIndexTemplateDelete(d *schema.ResourceData, meta interface{}) error {
id := d.Id()

var version string
var err error
switch client := meta.(type) {
case *elastic7.Client:
version, err = elastic7GetVersion(client)
if err == nil {
if version < "7.8.0" {
err = fmt.Errorf("index_template endpoint only available from ElasticSearch >= 7.8, got version %s", version)
} else {
err = elastic7DeleteIndexTemplate(client, id)
}
}
default:
err = fmt.Errorf("index_template endpoint only available from ElasticSearch >= 7.8, got version < 7.0.0")
}

if err != nil {
return err
}
d.SetId("")
return nil
}

func elastic7DeleteIndexTemplate(client *elastic7.Client, id string) error {
_, err := client.IndexDeleteIndexTemplate(id).Do(context.TODO())
return err
}

func resourceElasticsearchPutComposableIndexTemplate(d *schema.ResourceData, meta interface{}, create bool) error {
name := d.Get("name").(string)
body := d.Get("body").(string)

var err error
switch client := meta.(type) {
case *elastic7.Client:
err = elastic7PutIndexTemplate(client, name, body, create)
default:
err = fmt.Errorf("index_template endpoint only available from ElasticSearch >= 7.8, got version < 7.0.0")
}

return err
}

func elastic7PutIndexTemplate(client *elastic7.Client, name string, body string, create bool) error {
_, err := client.IndexPutIndexTemplate(name).BodyString(body).Create(create).Do(context.TODO())
return err
}
Loading