Closed nelg closed 4 years ago
Can you provide the (redacted) terraform resource config youβre using? What version of the provider are you using?
On Mon, Jan 20, 2020 at 9:09 PM Glen Ogilvie notifications@github.com wrote:
PUT %3Ctest-%7Bnow%2Fy%7Byyyy%7D%7D-000001%3E and DELETE %3Ctest-%7Bnow%2Fy%7Byyyy%7D%7D-000001%3E creates an index just fine, but the following does not work in Terraform.
resource "elasticsearch_index" "test" { name = "%3Ctest-%7Bnow%2Fy%7Byyyy%7D%7D-000001%3E" }
Docs:
https://www.elastic.co/guide/en/elasticsearch/reference/current/date-math-index-names.html
β You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/phillbaker/terraform-provider-elasticsearch/issues/55?email_source=notifications&email_token=AAAXCKN22IPTN7CSOPSDVW3Q6ZKMHA5CNFSM4KJMJI5KYY3PNVWWK3TUL52HS4DFUVEXG43VMWVGG33NNVSW45C7NFSM4IHPZC7A, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAXCKLR3C6G2QLSIYTQG3DQ6ZKMHANCNFSM4KJMJI5A .
Complete example:
provider "elasticsearch" {
url = var.elk_url
insecure = false # to bypass certificate check
username = var.username
password = var.password
cacert_file = "ap-southeast-2-aws-found-io-chain.pem"
}
resource "elasticsearch_index" "test" {
name = "%3Ctest-%7Bnow%2Fy%7Byyyy%7D%7D-000001%3E"
}
This is running against elasticsearch 7.5.0, and using latest terraform and latest terraform-provider-elasticsearch release.
The above should create an index, which uses date math to create the index named test-2020-000001
Can you provide the error output? Also, is the url escaping intentional?
On Tue, Jan 21, 2020 at 7:04 PM Glen Ogilvie notifications@github.com wrote:
Complete example:
provider "elasticsearch" { url = var.elk_url insecure = false # to bypass certificate check username = var.username password = var.password cacert_file = "ap-southeast-2-aws-found-io-chain.pem" } resource "elasticsearch_index" "test" { name = "%3Ctest-%7Bnow%2Fy%7Byyyy%7D%7D-000001%3E" }
This is running against elasticsearch 7.5.0, and using latest terraform and latest terraform-provider-elasticsearch release.
The above should create an index, which uses date math to create the index named test-2020-000001
β You are receiving this because you commented.
Reply to this email directly, view it on GitHub https://github.com/phillbaker/terraform-provider-elasticsearch/issues/55?email_source=notifications&email_token=AAAXCKKYHDB33VYQCB5EWF3Q66ESDA5CNFSM4KJMJI5KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEJRXXNA#issuecomment-576945076, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAXCKP7HGB2W6TC33TJZV3Q66ESDANCNFSM4KJMJI5A .
Hi,
The URL encoding was intentional, as it's standard to use URL encoding when making a request with a PUT command in Kibana/curl.
I've tried without URL encoding, ie:
resource "elasticsearch_index" "test" {
name = "<test-{now/y{yyyy}}-000001>"
}
Results are: With URL encoding, error is:
Error: elastic: Error 400 (Bad Request): Invalid index name [%3Ctest-%7Bnow%2Fy%7Byyyy%7D%7D-000001%3E], must be lowercase [type=invalid_index_name_exception]
Without URL encoding in the name: Terraform Plugin crashes, which crashes terraform. However the test-2020-000001 index actually does get created, so this makes me think that maybe the go libraries do the URL encoding themselves?
Terraform error, something like below. I've truncated the error a bit.
2020/01/22 21:49:56 [DEBUG] elasticsearch_index.test: apply errored, but we're indicating that via the Error pointer rather than returning it: rpc error: code = Unavailable desc = transport is closing
2020/01/22 21:49:56 [TRACE] <root>: eval: *terraform.EvalMaybeTainted
2020/01/22 21:49:56 [TRACE] EvalMaybeTainted: elasticsearch_index.test encountered an error during creation, so it is now marked as tainted
2020/01/22 21:49:56 [TRACE] <root>: eval: *terraform.EvalWriteState
2020/01/22 21:49:56 [TRACE] EvalWriteState: removing state object for elasticsearch_index.test
2020/01/22 21:49:56 [TRACE] <root>: eval: *terraform.EvalApplyProvisioners
2020/01/22 21:49:56 [TRACE] EvalApplyProvisioners: elasticsearch_index.test has no state, so skipping provisioners
2020/01/22 21:49:56 [TRACE] <root>: eval: *terraform.EvalMaybeTainted
2020/01/22 21:49:56 [TRACE] EvalMaybeTainted: elasticsearch_index.test encountered an error during creation, so it is now marked as tainted
2020/01/22 21:49:56 [TRACE] <root>: eval: *terraform.EvalWriteState
2020/01/22 21:49:56 [TRACE] EvalWriteState: removing state object for elasticsearch_index.test
2020/01/22 21:49:56 [TRACE] <root>: eval: *terraform.EvalIf
2020/01/22 21:49:56 [TRACE] <root>: eval: *terraform.EvalIf
2020/01/22 21:49:56 [TRACE] <root>: eval: *terraform.EvalWriteDiff
2020/01/22 21:49:56 [TRACE] <root>: eval: *terraform.EvalApplyPost
2020/01/22 21:49:56 [ERROR] <root>: eval: *terraform.EvalApplyPost, err: rpc error: code = Unavailable desc = transport is closing
2020/01/22 21:49:56 [ERROR] <root>: eval: *terraform.EvalSequence, err: rpc error: code = Unavailable desc = transport is closing
2020/01/22 21:49:56 [TRACE] [walkApply] Exiting eval tree: elasticsearch_index.test
2020/01/22 21:49:56 [TRACE] vertex "elasticsearch_index.test": visit complete
2020/01/22 21:49:56 [TRACE] dag/walk: upstream of "meta.count-boundary (EachMode fixup)" errored, so skipping
2020/01/22 21:49:56 [TRACE] dag/walk: upstream of "provider.elasticsearch (close)" errored, so skipping
2020/01/22 21:49:56 [TRACE] dag/walk: upstream of "root" errored, so skipping
maybe the go libraries do the URL encoding themselves?
Yup, they definitely should.
Thanks for the output - was it a go panic/was there any output from the go crash itself?
No go panic. Just a terraform crash.
The last line in the crash.log is: 2020-01-23T16:37:11.041+1300 [DEBUG] plugin: plugin exited before that, just stuff about statemgr.
This should be fairly straight forward to replicate if you have an elasticsearch to point terraform at. I'm pointing it at one on cloud.elastic.co.
It may be that the resource being created, ie, name = "<test-{now/y{yyyy}}-000001>" will be returning successful from elasticsearch, but the index name it makes is actually test-2020-000001.
Here is what the above resource creates:
GET %3Ctest-%7Bnow%2Fy%7Byyyy%7D%7D-000001%3E
"test-2020-000001" : {
"aliases" : { },
"mappings" : { },
"settings" : {
"index" : {
"routing" : {
"allocation" : {
"require" : {
"data" : "hot"
}
}
},
"number_of_shards" : "1",
"provided_name" : "<test-{now/y{yyyy}}-000001>",
"creation_date" : "1579750630243",
"number_of_replicas" : "1",
"uuid" : "NHIUSI8ySNqmxuXRpEEkog",
"version" : {
"created" : "7050099"
}
}
}
}
}
For state / knowing if the index should be created again / exists, the code might need to do a GET on the index name. It would be possible of course, in a years time, that the get returns no index, as it would look for test-2021-000001, so at that point, would create another one, which would be fine for my use case.
I can provide an example stack trace from the same issue:
2020-05-15T14:21:45.262Z [DEBUG] plugin.terraform-provider-elasticsearch: [signal SIGSEGV: segmentation violation code=0x1 addr=0x10 pc=0x1138b97]
2020-05-15T14:21:45.262Z [DEBUG] plugin.terraform-provider-elasticsearch:
2020-05-15T14:21:45.262Z [DEBUG] plugin.terraform-provider-elasticsearch: goroutine 90 [running]:
2020-05-15T14:21:45.262Z [DEBUG] plugin.terraform-provider-elasticsearch: github.com/phillbaker/terraform-provider-elasticsearch/es.resourceElasticsearchIndexRead(0xc00018a690, 0x14c1ee0, 0xc0002f6340, 0xc000448fe0, 0x0)
2020-05-15T14:21:45.262Z [DEBUG] plugin.terraform-provider-elasticsearch: /home/travis/gopath/src/github.com/phillbaker/terraform-provider-elasticsearch/es/resource_elasticsearch_index.go:303 +0x827
2020-05-15T14:21:45.263Z [DEBUG] plugin.terraform-provider-elasticsearch: github.com/phillbaker/terraform-provider-elasticsearch/es.resourceElasticsearchIndexCreate(0xc00018a690, 0x14c1ee0, 0xc0002f6340, 0x2, 0x23c1220)
2020-05-15T14:21:45.263Z [DEBUG] plugin.terraform-provider-elasticsearch: /home/travis/gopath/src/github.com/phillbaker/terraform-provider-elasticsearch/es/resource_elasticsearch_index.go:169 +0x25c
2020-05-15T14:21:45.263Z [DEBUG] plugin.terraform-provider-elasticsearch: github.com/hashicorp/terraform-plugin-sdk/helper/schema.(*Resource).Apply(0xc0000ecc00, 0xc0004ce640, 0xc000448b40, 0x14c1ee0, 0xc0002f6340, 0x1, 0xc0004bca60, 0x12bda00)
2020-05-15T14:21:45.263Z [DEBUG] plugin.terraform-provider-elasticsearch: /home/travis/gopath/pkg/mod/github.com/hashicorp/terraform-plugin-sdk@v1.0.0/helper/schema/resource.go:305 +0x3a7
2020-05-15T14:21:45.263Z [DEBUG] plugin.terraform-provider-elasticsearch: github.com/hashicorp/terraform-plugin-sdk/helper/schema.(*Provider).Apply(0xc0000ed480, 0xc0004dfa68, 0xc0004ce640, 0xc000448b40, 0xc000387ca8, 0xc000011668, 0x12c2aa0)
2020-05-15T14:21:45.263Z [DEBUG] plugin.terraform-provider-elasticsearch: /home/travis/gopath/pkg/mod/github.com/hashicorp/terraform-plugin-sdk@v1.0.0/helper/schema/provider.go:289 +0x18f
2020-05-15T14:21:45.263Z [DEBUG] plugin.terraform-provider-elasticsearch: github.com/hashicorp/terraform-plugin-sdk/internal/helper/plugin.(*GRPCProviderServer).ApplyResourceChange(0xc000010ae8, 0x17d97c0, 0xc0004bf920, 0xc00043d5c0, 0xc000010ae8, 0xc0004bf920, 0xc00043
7bd0)
2020-05-15T14:21:45.263Z [DEBUG] plugin.terraform-provider-elasticsearch: /home/travis/gopath/pkg/mod/github.com/hashicorp/terraform-plugin-sdk@v1.0.0/internal/helper/plugin/grpc_provider.go:885 +0x881
2020-05-15T14:21:45.263Z [DEBUG] plugin.terraform-provider-elasticsearch: github.com/hashicorp/terraform-plugin-sdk/internal/tfplugin5._Provider_ApplyResourceChange_Handler(0x143ab60, 0xc000010ae8, 0x17d97c0, 0xc0004bf920, 0xc00043d560, 0x0, 0x17d97c0, 0xc0004bf920, 0xc
0001a0a00, 0x263)
2020-05-15T14:21:45.263Z [DEBUG] plugin.terraform-provider-elasticsearch: /home/travis/gopath/pkg/mod/github.com/hashicorp/terraform-plugin-sdk@v1.0.0/internal/tfplugin5/tfplugin5.pb.go:3189 +0x23e
2020-05-15T14:21:45.263Z [DEBUG] plugin.terraform-provider-elasticsearch: google.golang.org/grpc.(*Server).processUnaryRPC(0xc0000ac000, 0x17e7e80, 0xc0003e3080, 0xc0004c6200, 0xc00008b0e0, 0x2395a80, 0x0, 0x0, 0x0)
2020-05-15T14:21:45.263Z [DEBUG] plugin.terraform-provider-elasticsearch: /home/travis/gopath/pkg/mod/google.golang.org/grpc@v1.23.0/server.go:995 +0x4ab
2020-05-15T14:21:45.263Z [DEBUG] plugin.terraform-provider-elasticsearch: google.golang.org/grpc.(*Server).handleStream(0xc0000ac000, 0x17e7e80, 0xc0003e3080, 0xc0004c6200, 0x0)
2020-05-15T14:21:45.263Z [DEBUG] plugin.terraform-provider-elasticsearch: /home/travis/gopath/pkg/mod/google.golang.org/grpc@v1.23.0/server.go:1275 +0xda6
2020-05-15T14:21:45.263Z [DEBUG] plugin.terraform-provider-elasticsearch: google.golang.org/grpc.(*Server).serveStreams.func1.1(0xc0000363d0, 0xc0000ac000, 0x17e7e80, 0xc0003e3080, 0xc0004c6200)
2020-05-15T14:21:45.263Z [DEBUG] plugin.terraform-provider-elasticsearch: /home/travis/gopath/pkg/mod/google.golang.org/grpc@v1.23.0/server.go:710 +0x9f
2020-05-15T14:21:45.263Z [DEBUG] plugin.terraform-provider-elasticsearch: created by google.golang.org/grpc.(*Server).serveStreams.func1
2020-05-15T14:21:45.263Z [DEBUG] plugin.terraform-provider-elasticsearch: /home/travis/gopath/pkg/mod/google.golang.org/grpc@v1.23.0/server.go:708 +0xa1
2020-05-15T14:21:45.263Z [DEBUG] plugin: plugin process exited: path=/home/{whoami}/terraform-provider-elasticsearch pid=9091 error="exit status 2"
The get fails (I believe) because the name is a dynamic name, where the "actual" elasticsesarch name ends up being static.
If we could search on provided_name
we could be in a much better place, but I'm not sure if it works that way.
e.g. elasticsearch ends up producing indices that look like:
{
"travis-testing-2020.05.14" : {
"aliases" : { },
"mappings" : { },
"settings" : {
"index" : {
"creation_date" : "1589491960906",
"number_of_shards" : "1",
"number_of_replicas" : "1",
"uuid" : "7nGyZ9DtRQ2q1kY-3rWR8g",
"version" : {
"created" : "7060299"
},
"provided_name" : "<travis-testing-{now/d}>"
}
}
}
}
When used with a *.tf
looking like:
resource "elasticsearch_index" "travis" {
name = "<travis-testing-{now/d}>"
}
Even with that fixed however, I have no idea how we should expect state management to work :(. We roll off indices after 1mo. In this case I'm only wanting to use terraform to create the initial indices (aka basically make sure the alias exists and points at "something"). But I don't know how we'd want to state to deal with that
The get fails (I believe) because the name is a dynamic name, where the "actual" elasticsesarch name ends up being static. If we could search on provided_name we could be in a much better place, but I'm not sure if it works that way.
I'm still surprised the get request is causing a segfault, but the reasoning makes sense. I'll take a look at provided_name.
In this case I'm only wanting to use terraform to create the initial indices (aka basically make sure the alias exists and points at "something")
Just to clarify, this is because following indices are created by index state management or curator?
But I don't know how we'd want to state to deal with that
This is a really good question, I can imagine several scenarios:
now()
I'm still surprised the get request is causing a segfault, but the reasoning makes sense. I'll take a look at provided_name.
Looking back at older versions of TPE I noticed we unsafely read the index
key from the response. I suspect I have an older version although I'm not sure how to confirm it outside of a sha1sum and comparing to other binaries π
So that's likely fixed at this point :)
Just to clarify, this is because following indices are created by index state management or curator?
Correct. For them to begin creating new indices, an initial (with an alias) must exist to start the whole process. All of the subsequent will be created by ILM, and eventually the index that I wanted terraform to create will roll off and no longer exist.
mimic the server side implementation and re-evaluate the date math at the current time now() this doesn't seem to match the terraform paradigm
I like the sound of this idea, but there's a nasty edge case that could bite.
I could -- if I were crazy -- we could have:
resource "elasticsearch_index_lifecycle_policy" "default" {
name = "default"
body = <<EOF
{
"policy": {
"phases": {
"hot": {
"actions": {
"rollover": {
"max_age": "45d"
}
}
}
}
EOF
}
resource "elasticsearch_index_template" "travis-testing" {
name = "nw-ops"
body = <<EOF
{
"index_patterns": [
"travis-testing-"
],
"settings": {
"index": {
"lifecycle": {
"name": "${elasticsearch_index_lifecycle_policy.default.name}",
"rollover_alias": "travis-testing"
}
}
}
}
EOF
}
resource "elasticsearch_index" "travis" {
name = "<travis-testing-{now/d}>"
aliases = "{\"travis-testing\": {\"is_write_index\": true}}"
}
In ^ when we create the "initial" index, we could end up with index travis-testing-2020-06-01
, but the next eligible index would be travis-testing-2020-07-15
. So we'd be seeing missing indices if we updated terraform state any time between those 45d.
That's a real convoluted example and is certainly not my use case. But is just a trade-off to make sure is conscious.
keep the evaluated time in the state and use that as the reference value this seems similar to the "initial index" use case this approach seems similar to how an autoscaling group in terraform treats instance creation, the initial pattern is applied and managed, but not the subsequent resources
I'm not sure I follow RE: what the evaluated time is for.
Thinking about it: what if -- when creating an index -- we inspect the output for a lifecycle policy (incase it was added to the template, not in the terraform code itself). IF it has that, AND used date math in the name, we track index.lifecycle.rollover_alias
instead? As long as there exists an index with the same alias and is_write_index: true
then terraform code for an "initial" index did its job.
It feels a little too dynamic for most terraform applications, but just a thought on something "stable" we can use for tracking.
Another option might be to add a "dont_look_for_me_in_elasticsearch" boolean flag in index where it only cares about the TF state, not the ES state π
Just to clarify, this is because following indices are created by index state management or curator?
Yes, the ILM policy creates new indices by copying the existing one, and then changing the alias to the new one.
But I don't know how we'd want to state to deal with that
This is a really good question, I can imagine several scenarios:
mimic the server side implementation and re-evaluate the date math at the current time
now()
- this doesn't seem to match the terraform paradigm
ensure that at least one index matching that pattern exists
keep the evaluated time in the state and use that as the reference value
- this seems similar to the "initial index" use case
- this approach seems similar to how an autoscaling group in terraform treats instance creation, the initial pattern is applied and managed, but not the subsequent resources
Thinking about this some more, my thoughts are. Indices like this, are usually needed for ILM policies. We could add a parameter to the resource elasticsearch_index_lifecycle_policy, that allows the creation of the initial index using date math. I the index creation was embedded in the elasticsearch_index_lifecycle_policy, it would only then get run when the index policy was modified / created. When it does run, it would however still need to do a search to very that the index pattern did not already exist before creating it.
For the general elasticsearch_index resource.: My view is:
Thanks for the thoughts @travisby @nelg.
I noticed we unsafely read the index key from the response. I suspect I have an older version
That's still done on master: https://github.com/phillbaker/terraform-provider-elasticsearch/blob/9cd2c48d35079b29e7e369ea8dcad6442de1ebf4/es/resource_elasticsearch_index.go#L309
When re-running applies, search for the index by the pattern name.
I think you meant provided_name
? If so, it looks like there's not a good way to search for this, we'd have to use the indices cat endpoint and then N+1 retrieve each individual index.
Indices like this, are usually needed for ILM policies. We could add a parameter to the resource elasticsearch_index_lifecycle_policy, that allows the creation of the initial index using date math. I the index creation was embedded in the elasticsearch_index_lifecycle_policy, it would only then get run when the index policy was modified / created. When it does run, it would however still need to do a search to very that the index pattern did not already exist before creating it.
This is interesting, it might also tie in with the suggestion to use index.lifecycle.rollover_alias
above. However, we'd still need to either do our own matching of index names to the pattern or N+1 to look at all indices' provided_name
.
For the general elasticsearch_index resource.: My view is:
create it using the pattern (don't try and have the provider guess what the actual index name is, or do any evaluation of the name when it date math pattern).
check that the index created has the provided_name set.
When re-running applies, search for the index by the pattern name. If it does not exist, create it and update the state, effectively forgetting about the old one that was made when the pattern evaluated to something else. This is kind of would happen if someone manually deleted an index anyway.
This makes sense to me.
When re-running applies, search for the index by the pattern name. I think you meant provided_name? If so, it looks like there's not a good way to search for this, we'd have to use the indices cat endpoint and then N+1 retrieve each individual index.
No, I mean search for it by the pattern name. Ie, send the following request to elasticsearch.
GET %3Ctest-%7Bnow%2Fy%7Byyyy%7D%7D-000001%3E
Elasticsearch will then do the date math, and return you the matching index, ie:
{
"test-2020-000001" : {
"aliases" : { },
"mappings" : { },
"settings": {
"provided_name" : "<test-{now/y{yyyy}}-000001>"
}
}
So, the get \<pattern> will return an index that's name is the resolved pattern. When we do a get for this index, an optional check we could do, is that if the provided name exists, that it matches the url encoded
The main trick here, is that the index returned, is the resolved name, so that the name we know it by (the pattern), and the resolved name, are different.
I think, we should basically accept that, if we search for the pattern, and we get an index back, then we can consider it exists and we don't need to re-create it, regardless of it we made the new one, or if it was created by ILM. If we search for the pattern and it returns no records, then we need to create an index, even if some older index existed when our pattern resolved to a different date based index name.
The main trick here, is that the index returned, is the resolved name, so that the name we know it by (the pattern), and the resolved name, are different. I think, we should basically accept that, if we search for the pattern, and we get an index back, then we can consider it exists and we don't need to re-create it, regardless of it we made the new one, or if it was created by ILM. If we search for the pattern and it returns no records, then we need to create an index, even if some older index existed when our pattern resolved to a different date based index name.
I understand the thinking here, but I'm reconsidering if this makes sense with terraform's model. Given the that other settings can change on an index and that date math could be used for daily indices, I think the conservative approach is to have terraform state map to the original created index. In some regards, having multiple services manage these indices is a bit outside of the "pure terraform" approach. This upstream functionality may be related: https://github.com/hashicorp/terraform/issues/15485
I've pushed a fix along these lines in 47c241cc5957bcaaf9ee9a6577c6d709217ce958
This was fixed and released in https://github.com/phillbaker/terraform-provider-elasticsearch/blob/master/CHANGELOG.md#130---2020-06-20, opened https://github.com/phillbaker/terraform-provider-elasticsearch/issues/75 for the additional functionality discussed.
PUT %3Ctest-%7Bnow%2Fy%7Byyyy%7D%7D-000001%3E
andDELETE %3Ctest-%7Bnow%2Fy%7Byyyy%7D%7D-000001%3E
creates an index just fine, but the following does not work in Terraform.Docs: https://www.elastic.co/guide/en/elasticsearch/reference/current/date-math-index-names.html