From 82d1dfc72b3b5abb139e5ca94a3761959acba5e9 Mon Sep 17 00:00:00 2001 From: Alexandre Nicolaie dit Clairville Date: Thu, 3 Feb 2022 18:09:05 +0100 Subject: [PATCH 1/4] Implement naively component template --- internal/clients/index.go | 63 ++++ .../elasticsearch/index/component_template.go | 294 ++++++++++++++++++ .../index/component_template_test.go | 76 +++++ internal/models/models.go | 16 + internal/provider/provider.go | 1 + 5 files changed, 450 insertions(+) create mode 100644 internal/elasticsearch/index/component_template.go create mode 100644 internal/elasticsearch/index/component_template_test.go diff --git a/internal/clients/index.go b/internal/clients/index.go index 2a0f50e29..bee45609f 100644 --- a/internal/clients/index.go +++ b/internal/clients/index.go @@ -79,6 +79,69 @@ func (a *ApiClient) DeleteElasticsearchIlm(policyName string) diag.Diagnostics { return diags } +func (a *ApiClient) PutElasticsearchComponentTemplate(template *models.ComponentTemplate) diag.Diagnostics { + var diags diag.Diagnostics + templateBytes, err := json.Marshal(template) + if err != nil { + return diag.FromErr(err) + } + log.Printf("[TRACE] sending request to ES: %s to create component template '%s' ", templateBytes, template.Name) + + res, err := a.es.Cluster.PutComponentTemplate(template.Name, bytes.NewReader(templateBytes)) + if err != nil { + return diag.FromErr(err) + } + defer res.Body.Close() + if diags := utils.CheckError(res, "Unable to create component template"); diags.HasError() { + return diags + } + + return diags +} + +func (a *ApiClient) GetElasticsearchComponentTemplate(templateName string) (*models.ComponentTemplateResponse, diag.Diagnostics) { + var diags diag.Diagnostics + req := a.es.Cluster.GetComponentTemplate.WithName(templateName) + res, err := a.es.Cluster.GetComponentTemplate(req) + if err != nil { + return nil, diag.FromErr(err) + } + defer res.Body.Close() + if diags := utils.CheckError(res, "Unable to request index template."); diags.HasError() { + return nil, diags + } + + var componentTemplates models.ComponentTemplatesResponse + if err := json.NewDecoder(res.Body).Decode(&componentTemplates); err != nil { + return nil, diag.FromErr(err) + } + + // we requested only 1 template + if len(componentTemplates.ComponentTemplates) != 1 { + diags = append(diags, diag.Diagnostic{ + Severity: diag.Error, + Summary: "Wrong number of templates returned", + Detail: fmt.Sprintf("Elasticsearch API returned %d when requested '%s' component template.", len(componentTemplates.ComponentTemplates), templateName), + }) + return nil, diags + } + tpl := componentTemplates.ComponentTemplates[0] + return &tpl, diags +} + +func (a *ApiClient) DeleteElasticsearchComponentTemplate(templateName string) diag.Diagnostics { + var diags diag.Diagnostics + res, err := a.es.Cluster.DeleteComponentTemplate(templateName) + if err != nil { + return diag.FromErr(err) + } + defer res.Body.Close() + if diags := utils.CheckError(res, "Unable to delete component template"); diags.HasError() { + return diags + } + return diags +} + func (a *ApiClient) PutElasticsearchIndexTemplate(template *models.IndexTemplate) diag.Diagnostics { var diags diag.Diagnostics templateBytes, err := json.Marshal(template) diff --git a/internal/elasticsearch/index/component_template.go b/internal/elasticsearch/index/component_template.go new file mode 100644 index 000000000..01ec62f9a --- /dev/null +++ b/internal/elasticsearch/index/component_template.go @@ -0,0 +1,294 @@ +package index + +import ( + "context" + "encoding/json" + "strings" + + "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-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func ResourceComponentTemplate() *schema.Resource { + // NOTE: component_template and index_template uses the same schema + componentTemplateSchema := map[string]*schema.Schema{ + "id": { + Description: "Internal identifier of the resource", + Type: schema.TypeString, + Computed: true, + }, + "name": { + Description: "Name of the component template to create.", + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "metadata": { + Description: "Optional user metadata about the component template.", + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringIsJSON, + DiffSuppressFunc: utils.DiffJsonSuppress, + }, + "template": { + Description: "Template to be applied. It may optionally include an aliases, mappings, or settings configuration.", + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "alias": { + Description: "Alias to add.", + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Description: "The alias name. Index alias names support date math. See, https://www.elastic.co/guide/en/elasticsearch/reference/current/date-math-index-names.html", + Type: schema.TypeString, + Required: true, + }, + "filter": { + Description: "Query used to limit documents the alias can access.", + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: utils.DiffJsonSuppress, + ValidateFunc: validation.StringIsJSON, + }, + "index_routing": { + Description: "Value used to route indexing operations to a specific shard. If specified, this overwrites the routing value for indexing operations.", + Type: schema.TypeString, + Optional: true, + }, + "is_hidden": { + Description: "If true, the alias is hidden.", + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "is_write_index": { + Description: "If true, the index is the write index for the alias.", + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "routing": { + Description: "Value used to route indexing and search operations to a specific shard.", + Type: schema.TypeString, + Optional: true, + }, + "search_routing": { + Description: "Value used to route search operations to a specific shard. If specified, this overwrites the routing value for search operations.", + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "mappings": { + Description: "Mapping for fields in the index.", + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: utils.DiffJsonSuppress, + ValidateFunc: validation.StringIsJSON, + }, + "settings": { + Description: "Configuration options for the index. See, https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules.html#index-modules-settings", + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: utils.DiffIndexSettingSuppress, + ValidateFunc: validation.StringIsJSON, + }, + }, + }, + }, + "version": { + Description: "Version number used to manage component templates externally.", + Type: schema.TypeInt, + Optional: true, + }, + } + + utils.AddConnectionSchema(componentTemplateSchema) + + return &schema.Resource{ + Description: "Creates or updates a component template. Component templates are building blocks for constructing index templates that specify index mappings, settings, and aliases. See, https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-component-template.html", + + CreateContext: resourceComponentTemplatePut, + UpdateContext: resourceComponentTemplatePut, + ReadContext: resourceComponentTemplateRead, + DeleteContext: resourceComponentTemplateDelete, + + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Schema: componentTemplateSchema, + } +} + +func resourceComponentTemplatePut(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client, err := clients.NewApiClient(d, meta) + if err != nil { + return diag.FromErr(err) + } + componentId := d.Get("name").(string) + id, diags := client.ID(componentId) + if diags.HasError() { + return diags + } + var componentTemplate models.ComponentTemplate + componentTemplate.Name = componentId + + if v, ok := d.GetOk("metadata"); ok { + metadata := make(map[string]interface{}) + if err := json.NewDecoder(strings.NewReader(v.(string))).Decode(&metadata); err != nil { + return diag.FromErr(err) + } + componentTemplate.Meta = metadata + } + + if v, ok := d.GetOk("template"); ok { + // only one template block allowed to be declared + definedTempl := v.([]interface{})[0].(map[string]interface{}) + definedAliases := definedTempl["alias"].(*schema.Set) + templ := models.Template{} + + aliases := make(map[string]models.IndexAlias, definedAliases.Len()) + for _, a := range definedAliases.List() { + alias := a.(map[string]interface{}) + templAlias := models.IndexAlias{} + + if f, ok := alias["filter"]; ok { + if f.(string) != "" { + filterMap := make(map[string]interface{}) + if err := json.Unmarshal([]byte(f.(string)), &filterMap); err != nil { + return diag.FromErr(err) + } + templAlias.Filter = filterMap + } + } + if ir, ok := alias["index_routing"]; ok { + templAlias.IndexRouting = ir.(string) + } + templAlias.IsHidden = alias["is_hidden"].(bool) + templAlias.IsWriteIndex = alias["is_write_index"].(bool) + if r, ok := alias["routing"]; ok { + templAlias.Routing = r.(string) + } + if sr, ok := alias["search_routing"]; ok { + templAlias.SearchRouting = sr.(string) + } + + aliases[alias["name"].(string)] = templAlias + } + templ.Aliases = aliases + + if mappings, ok := definedTempl["mappings"]; ok { + if mappings.(string) != "" { + maps := make(map[string]interface{}) + if err := json.Unmarshal([]byte(mappings.(string)), &maps); err != nil { + return diag.FromErr(err) + } + templ.Mappings = maps + } + } + + if settings, ok := definedTempl["settings"]; ok { + if settings.(string) != "" { + sets := make(map[string]interface{}) + if err := json.Unmarshal([]byte(settings.(string)), &sets); err != nil { + return diag.FromErr(err) + } + templ.Settings = sets + } + } + + componentTemplate.Template = &templ + } + + if v, ok := d.GetOk("version"); ok { + definedVer := v.(int) + componentTemplate.Version = &definedVer + } + + if diags := client.PutElasticsearchComponentTemplate(&componentTemplate); diags.HasError() { + return diags + } + + d.SetId(id.String()) + return resourceComponentTemplateRead(ctx, d, meta) +} + +func resourceComponentTemplateRead(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) + } + compId, diags := clients.CompositeIdFromStr(d.Id()) + if diags.HasError() { + return diags + } + templateId := compId.ResourceId + + tpl, diags := client.GetElasticsearchComponentTemplate(templateId) + if diags.HasError() { + return diags + } + + // set the fields + if err := d.Set("name", tpl.Name); err != nil { + return diag.FromErr(err) + } + + if tpl.ComponentTemplate.Meta != nil { + metadata, err := json.Marshal(tpl.ComponentTemplate.Meta) + if err != nil { + return diag.FromErr(err) + } + if err := d.Set("metadata", string(metadata)); err != nil { + return diag.FromErr(err) + } + } + + if tpl.ComponentTemplate.Template != nil { + template, diags := flattenTemplateData(tpl.ComponentTemplate.Template) + if diags.HasError() { + return diags + } + + if err := d.Set("template", template); err != nil { + return diag.FromErr(err) + } + } + + if err := d.Set("version", tpl.ComponentTemplate.Version); err != nil { + return diag.FromErr(err) + } + + return diags +} + +func resourceComponentTemplateDelete(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 + } + if diags := client.DeleteElasticsearchComponentTemplate(compId.ResourceId); diags.HasError() { + return diags + } + d.SetId("") + return diags +} diff --git a/internal/elasticsearch/index/component_template_test.go b/internal/elasticsearch/index/component_template_test.go new file mode 100644 index 000000000..5739ac3be --- /dev/null +++ b/internal/elasticsearch/index/component_template_test.go @@ -0,0 +1,76 @@ +package index_test + +import ( + "fmt" + "testing" + + "github.com/elastic/terraform-provider-elasticstack/internal/acctest" + "github.com/elastic/terraform-provider-elasticstack/internal/clients" + sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccResourceComponentTemplate(t *testing.T) { + // generate a random username + templateName := sdkacctest.RandStringFromCharSet(10, sdkacctest.CharSetAlphaNum) + + resource.UnitTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + CheckDestroy: checkResourceComponentTemplateDestroy, + ProviderFactories: acctest.Providers, + Steps: []resource.TestStep{ + { + Config: testAccResourceComponentTemplateCreate(templateName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("elasticstack_elasticsearch_component_template.test", "name", templateName), + resource.TestCheckResourceAttr("elasticstack_elasticsearch_component_template.test", "template.0.alias.0.name", "my_template_test"), + resource.TestCheckResourceAttr("elasticstack_elasticsearch_component_template.test", "template.0.settings", `{"index":{"number_of_shards":"3"}}`), + ), + }, + }, + }) +} + +func testAccResourceComponentTemplateCreate(name string) string { + return fmt.Sprintf(` +provider "elasticstack" { + elasticsearch {} +} + +resource "elasticstack_elasticsearch_component_template" "test" { + name = "%s" + + template { + alias { + name = "my_template_test" + } + + settings = jsonencode({ + number_of_shards = "3" + }) + } +}`, name) +} + +func checkResourceComponentTemplateDestroy(s *terraform.State) error { + client := acctest.Provider.Meta().(*clients.ApiClient) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "elasticstack_elasticsearch_component_template" { + continue + } + compId, _ := clients.CompositeIdFromStr(rs.Primary.ID) + + req := client.GetESClient().Cluster.GetComponentTemplate.WithName(compId.ResourceId) + res, err := client.GetESClient().Cluster.GetComponentTemplate(req) + if err != nil { + return err + } + + if res.StatusCode != 404 { + return fmt.Errorf("Component template (%s) still exists", compId.ResourceId) + } + } + return nil +} diff --git a/internal/models/models.go b/internal/models/models.go index a75ac8254..2ad83ca95 100644 --- a/internal/models/models.go +++ b/internal/models/models.go @@ -67,6 +67,22 @@ type IndexTemplateResponse struct { IndexTemplate IndexTemplate `json:"index_template"` } +type ComponentTemplate struct { + Name string `json:"-"` + Meta map[string]interface{} `json:"_meta,omitempty"` + Template *Template `json:"template,omitempty"` + Version *int `json:"version,omitempty"` +} + +type ComponentTemplatesResponse struct { + ComponentTemplates []ComponentTemplateResponse `json:"component_templates"` +} + +type ComponentTemplateResponse struct { + Name string `json:"name"` + ComponentTemplate ComponentTemplate `json:"component_template"` +} + type PolicyDefinition struct { Policy Policy `json:"policy"` Modified string `json:"modified_date"` diff --git a/internal/provider/provider.go b/internal/provider/provider.go index f6ecb80d9..b693f4165 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -70,6 +70,7 @@ func New(version string) func() *schema.Provider { }, ResourcesMap: map[string]*schema.Resource{ "elasticstack_elasticsearch_cluster_settings": cluster.ResourceSettings(), + "elasticstack_elasticsearch_component_template": index.ResourceComponentTemplate(), "elasticstack_elasticsearch_data_stream": index.ResourceDataStream(), "elasticstack_elasticsearch_index": index.ResourceIndex(), "elasticstack_elasticsearch_index_lifecycle": index.ResourceIlm(), From de1583082052fe6208eecfdd8100640527a78fe4 Mon Sep 17 00:00:00 2001 From: Alexandre Nicolaie dit Clairville Date: Thu, 3 Feb 2022 18:11:02 +0100 Subject: [PATCH 2/4] Add example and update docs --- .../elasticsearch_component_template.md | 104 ++++++++++++++++++ .../import.sh | 1 + .../resource.tf | 24 ++++ .../elasticsearch_component_template.md.tmpl | 23 ++++ 4 files changed, 152 insertions(+) create mode 100644 docs/resources/elasticsearch_component_template.md create mode 100644 examples/resources/elasticstack_elasticsearch_component_template/import.sh create mode 100644 examples/resources/elasticstack_elasticsearch_component_template/resource.tf create mode 100644 templates/resources/elasticsearch_component_template.md.tmpl diff --git a/docs/resources/elasticsearch_component_template.md b/docs/resources/elasticsearch_component_template.md new file mode 100644 index 000000000..e7acc3ac0 --- /dev/null +++ b/docs/resources/elasticsearch_component_template.md @@ -0,0 +1,104 @@ +--- +subcategory: "Index" +layout: "" +page_title: "Elasticstack: elasticstack_elasticsearch_component_template Resource" +description: |- + Creates or updates a component template. +--- + +# Resource: elasticstack_elasticsearch_component_template + +Creates or updates a component template. Component templates are building blocks for constructing index templates that specify index mappings, settings, and aliases. See, https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-component-template.html + +## Example Usage + +```terraform +provider "elasticstack" { + elasticsearch {} +} + +resource "elasticstack_elasticsearch_component_template" "my_template" { + name = "my_template" + + template { + aliases { + name = "my_template_test" + } + + settings = jsonencode({ + number_of_shards = "3" + }) + } +} + +resource "elasticstack_elasticsearch_index_template" "my_template" { + name = "my_data_stream" + + index_patterns = ["stream*"] + composed_of = [elasticstack_elasticsearch_component_template.my_template.name] +} +``` + + +## Schema + +### Required + +- **name** (String) Name of the component template to create. +- **template** (Block List, Min: 1, Max: 1) Template to be applied. It may optionally include an aliases, mappings, or settings configuration. (see [below for nested schema](#nestedblock--template)) + +### Optional + +- **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)) +- **metadata** (String) Optional user metadata about the component template. +- **version** (Number) Version number used to manage component templates externally. + +### Read-Only + +- **id** (String) Internal identifier of the resource + + +### Nested Schema for `template` + +Optional: + +- **alias** (Block Set) Alias to add. (see [below for nested schema](#nestedblock--template--alias)) +- **mappings** (String) Mapping for fields in the index. +- **settings** (String) Configuration options for the index. See, https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules.html#index-modules-settings + + +### Nested Schema for `template.alias` + +Required: + +- **name** (String) The alias name. Index alias names support date math. See, https://www.elastic.co/guide/en/elasticsearch/reference/current/date-math-index-names.html + +Optional: + +- **filter** (String) Query used to limit documents the alias can access. +- **index_routing** (String) Value used to route indexing operations to a specific shard. If specified, this overwrites the routing value for indexing operations. +- **is_hidden** (Boolean) If true, the alias is hidden. +- **is_write_index** (Boolean) If true, the index is the write index for the alias. +- **routing** (String) Value used to route indexing and search operations to a specific shard. +- **search_routing** (String) Value used to route search operations to a specific shard. If specified, this overwrites the routing value for search operations. + + + + +### Nested Schema for `elasticsearch_connection` + +Optional: + +- **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_component_template.my_template / +``` diff --git a/examples/resources/elasticstack_elasticsearch_component_template/import.sh b/examples/resources/elasticstack_elasticsearch_component_template/import.sh new file mode 100644 index 000000000..a68a2436c --- /dev/null +++ b/examples/resources/elasticstack_elasticsearch_component_template/import.sh @@ -0,0 +1 @@ +terraform import elasticstack_elasticsearch_component_template.my_template / diff --git a/examples/resources/elasticstack_elasticsearch_component_template/resource.tf b/examples/resources/elasticstack_elasticsearch_component_template/resource.tf new file mode 100644 index 000000000..f3565a994 --- /dev/null +++ b/examples/resources/elasticstack_elasticsearch_component_template/resource.tf @@ -0,0 +1,24 @@ +provider "elasticstack" { + elasticsearch {} +} + +resource "elasticstack_elasticsearch_component_template" "my_template" { + name = "my_template" + + template { + aliases { + name = "my_template_test" + } + + settings = jsonencode({ + number_of_shards = "3" + }) + } +} + +resource "elasticstack_elasticsearch_index_template" "my_template" { + name = "my_data_stream" + + index_patterns = ["stream*"] + composed_of = [elasticstack_elasticsearch_component_template.my_template.name] +} diff --git a/templates/resources/elasticsearch_component_template.md.tmpl b/templates/resources/elasticsearch_component_template.md.tmpl new file mode 100644 index 000000000..a1e9d7830 --- /dev/null +++ b/templates/resources/elasticsearch_component_template.md.tmpl @@ -0,0 +1,23 @@ +--- +subcategory: "Index" +layout: "" +page_title: "Elasticstack: elasticstack_elasticsearch_component_template Resource" +description: |- + Creates or updates a component template. +--- + +# Resource: elasticstack_elasticsearch_component_template + +Creates or updates a component template. Component templates are building blocks for constructing index templates that specify index mappings, settings, and aliases. See, https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-component-template.html + +## Example Usage + +{{ tffile "examples/resources/elasticstack_elasticsearch_component_template/resource.tf" }} + +{{ .SchemaMarkdown | trimspace }} + +## Import + +Import is supported using the following syntax: + +{{ codefile "shell" "examples/resources/elasticstack_elasticsearch_component_template/import.sh" }} From 3e6ca3e809d0c1000096a2556f86b9e595f1464f Mon Sep 17 00:00:00 2001 From: Alexandre Nicolaie dit Clairville Date: Sat, 5 Feb 2022 17:59:17 +0100 Subject: [PATCH 3/4] Update CHANGELOG: support component template resources --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d1795ea4..6986696ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### Added - New resource `elasticstack_elasticsearch_data_stream` to manage Elasticsearch [data streams](https://www.elastic.co/guide/en/elasticsearch/reference/current/data-streams.html) ([#45](https://github.com/elastic/terraform-provider-elasticstack/pull/45)) - New resource `elasticstack_elasticsearch_ingest_pipeline` to manage Elasticsearch [ingest pipelines](https://www.elastic.co/guide/en/elasticsearch/reference/7.16/ingest.html) ([#56](https://github.com/elastic/terraform-provider-elasticstack/issues/56)) +- New resource `elasticstack_elasticsearch_component_template` to manage Elasticsearch [component templates](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-component-template.html) ([#39](https://github.com/elastic/terraform-provider-elasticstack/pull/39)) ### Fixed - Update only changed index settings ([#52](https://github.com/elastic/terraform-provider-elasticstack/issues/52)) From dc34ed0edc85de4a7a83572f809cb40c66c35e62 Mon Sep 17 00:00:00 2001 From: Alexandre NICOLAIE Date: Thu, 10 Feb 2022 08:54:50 +0100 Subject: [PATCH 4/4] Apply GH review suggestion Co-authored-by: Oleksandr --- internal/clients/index.go | 3 +++ internal/elasticsearch/index/component_template.go | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/internal/clients/index.go b/internal/clients/index.go index bee45609f..15a42251d 100644 --- a/internal/clients/index.go +++ b/internal/clients/index.go @@ -107,6 +107,9 @@ func (a *ApiClient) GetElasticsearchComponentTemplate(templateName string) (*mod return nil, diag.FromErr(err) } defer res.Body.Close() + if res.StatusCode == http.StatusNotFound { + return nil, nil + } if diags := utils.CheckError(res, "Unable to request index template."); diags.HasError() { return nil, diags } diff --git a/internal/elasticsearch/index/component_template.go b/internal/elasticsearch/index/component_template.go index 01ec62f9a..dbb34b906 100644 --- a/internal/elasticsearch/index/component_template.go +++ b/internal/elasticsearch/index/component_template.go @@ -237,6 +237,10 @@ func resourceComponentTemplateRead(ctx context.Context, d *schema.ResourceData, templateId := compId.ResourceId tpl, diags := client.GetElasticsearchComponentTemplate(templateId) + if tpl == nil && diags == nil { + d.SetId("") + return diags + } if diags.HasError() { return diags }