├── .github └── workflows │ └── test.yml ├── .gitignore ├── .golangci.yml ├── .goreleaser.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── docker-compose.yml ├── docs ├── data-sources │ ├── host.md │ └── opensearch_destination.md ├── guides │ └── rollover.md ├── index.md └── resources │ ├── cluster_settings.md │ ├── component_template.md │ ├── composable_index_template.md │ ├── data_stream.md │ ├── index.md │ ├── index_template.md │ ├── ingest_pipeline.md │ ├── kibana_alert.md │ ├── kibana_object.md │ ├── opensearch_audit_config.md │ ├── opensearch_destination.md │ ├── opensearch_ism_policy.md │ ├── opensearch_ism_policy_mapping.md │ ├── opensearch_kibana_tenant.md │ ├── opensearch_monitor.md │ ├── opensearch_role.md │ ├── opensearch_roles_mapping.md │ ├── opensearch_user.md │ ├── script.md │ ├── snapshot_repository.md │ ├── xpack_index_lifecycle_policy.md │ ├── xpack_license.md │ ├── xpack_role.md │ ├── xpack_role_mapping.md │ ├── xpack_snapshot_lifecycle_policy.md │ ├── xpack_user.md │ └── xpack_watch.md ├── es ├── data_source_elasticsearch_host.go ├── data_source_elasticsearch_host_test.go ├── data_source_elasticsearch_opendistro_destination.go ├── data_source_elasticsearch_opendistro_destination_test.go ├── diff_suppress_funcs.go ├── http.go ├── provider.go ├── provider_test.go ├── resource_elasticsearch_audit_config.go ├── resource_elasticsearch_audit_config_test.go ├── resource_elasticsearch_cluster_settings.go ├── resource_elasticsearch_cluster_settings_test.go ├── resource_elasticsearch_component_template.go ├── resource_elasticsearch_component_template_test.go ├── resource_elasticsearch_composable_index_template.go ├── resource_elasticsearch_composable_index_template_test.go ├── resource_elasticsearch_data_stream.go ├── resource_elasticsearch_data_stream_test.go ├── resource_elasticsearch_index.go ├── resource_elasticsearch_index_template.go ├── resource_elasticsearch_index_template_test.go ├── resource_elasticsearch_index_test.go ├── resource_elasticsearch_ingest_pipeline.go ├── resource_elasticsearch_ingest_pipeline_test.go ├── resource_elasticsearch_kibana_alert.go ├── resource_elasticsearch_kibana_alert_test.go ├── resource_elasticsearch_kibana_object.go ├── resource_elasticsearch_kibana_object_test.go ├── resource_elasticsearch_opendistro_destination.go ├── resource_elasticsearch_opendistro_destination_test.go ├── resource_elasticsearch_opendistro_ism_policy.go ├── resource_elasticsearch_opendistro_ism_policy_mapping.go ├── resource_elasticsearch_opendistro_ism_policy_mapping_test.go ├── resource_elasticsearch_opendistro_ism_policy_test.go ├── resource_elasticsearch_opendistro_kibana_tenant.go ├── resource_elasticsearch_opendistro_kibana_tenant_test.go ├── resource_elasticsearch_opendistro_monitor.go ├── resource_elasticsearch_opendistro_monitor_test.go ├── resource_elasticsearch_opendistro_role.go ├── resource_elasticsearch_opendistro_role_test.go ├── resource_elasticsearch_opendistro_roles_mapping.go ├── resource_elasticsearch_opendistro_roles_mapping_test.go ├── resource_elasticsearch_opendistro_user.go ├── resource_elasticsearch_opendistro_user_test.go ├── resource_elasticsearch_script.go ├── resource_elasticsearch_script_test.go ├── resource_elasticsearch_snapshot_repository.go ├── resource_elasticsearch_snapshot_repository_test.go ├── resource_elasticsearch_xpack_index_lifecycle_policy.go ├── resource_elasticsearch_xpack_index_lifecycle_policy_test.go ├── resource_elasticsearch_xpack_license.go ├── resource_elasticsearch_xpack_license_test.go ├── resource_elasticsearch_xpack_role.go ├── resource_elasticsearch_xpack_role_mapping.go ├── resource_elasticsearch_xpack_role_mapping_test.go ├── resource_elasticsearch_xpack_role_test.go ├── resource_elasticsearch_xpack_snapshot_lifecycle_policy.go ├── resource_elasticsearch_xpack_snapshot_lifecycle_policy_test.go ├── resource_elasticsearch_xpack_user.go ├── resource_elasticsearch_xpack_user_test.go ├── resource_elasticsearch_xpack_watch.go ├── resource_elasticsearch_xpack_watch_test.go └── util.go ├── examples ├── README.md ├── data-sources │ ├── elasticsearch_host │ │ └── data-source.tf │ └── elasticsearch_opensearch_destination │ │ └── data-source.tf ├── ingest_pipeline │ └── main.tf └── resources │ ├── elasticsearch_audit_config │ ├── import.sh │ └── resource.tf │ ├── elasticsearch_cluster_settings │ └── resource.tf │ ├── elasticsearch_component_template │ ├── import.sh │ └── resource.tf │ ├── elasticsearch_data_stream │ └── resource.tf │ ├── elasticsearch_index │ ├── import.sh │ └── resource.tf │ ├── elasticsearch_kibana_alert │ ├── import.sh │ └── resource.tf │ ├── elasticsearch_opensearch_destination │ ├── import.sh │ └── resource.tf │ ├── elasticsearch_opensearch_ism_policy_mapping │ ├── import.sh │ └── resource.tf │ ├── elasticsearch_xpack_role_mapping │ ├── import.sh │ └── resource.tf │ ├── elasticsearch_xpack_snapshot_lifecycle_policy │ ├── import.sh │ └── resource.tf │ └── elasticsearch_xpack_user │ ├── import.sh │ └── resource.tf ├── go.mod ├── go.sum ├── kibana └── alerts.go ├── main.go ├── script ├── install-tools ├── test-mod-tidy ├── test-terraform-fmt └── wait-for-endpoint ├── test_aws_config └── tools └── tools.go /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | linters: 2 | enable: 3 | - gofmt 4 | 5 | issues: 6 | exclude-rules: 7 | - linters: 8 | - staticcheck 9 | text: "SA1019:" 10 | path: es/resource_elasticsearch_index_template.*.go 11 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | # Visit https://goreleaser.com for documentation on how to customize this 2 | # behavior. 3 | before: 4 | hooks: 5 | - go mod tidy 6 | builds: 7 | - env: 8 | - CGO_ENABLED=0 9 | mod_timestamp: '{{ .CommitTimestamp }}' 10 | flags: 11 | - -trimpath 12 | ldflags: 13 | - '-s -w -X main.version={{.Version}} -X main.commit={{.Commit}}' 14 | goos: 15 | - freebsd 16 | - windows 17 | - linux 18 | - darwin 19 | goarch: 20 | - amd64 21 | - '386' 22 | - arm 23 | - arm64 24 | ignore: 25 | - goos: darwin 26 | goarch: '386' 27 | binary: '{{ .ProjectName }}_v{{ .Version }}' 28 | archives: 29 | - format: zip 30 | name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}' 31 | checksum: 32 | name_template: '{{ .ProjectName }}_{{ .Version }}_SHA256SUMS' 33 | algorithm: sha256 34 | signs: 35 | - artifacts: checksum 36 | args: 37 | # pass the batch flag to indicate its not interactive. 38 | - "--batch" 39 | - "--local-user" 40 | - "{{ .Env.GPG_FINGERPRINT }}" 41 | - "--output" 42 | - "${signature}" 43 | - "--detach-sign" 44 | - "${artifact}" 45 | release: 46 | draft: false 47 | changelog: 48 | skip: true 49 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | elasticsearch: 5 | image: ${OSS_IMAGE} 6 | hostname: elasticsearch 7 | container_name: elasticsearch 8 | networks: 9 | - elasticsearch # used by ESv6 kibana 10 | environment: 11 | - cluster.name=elasticsearch 12 | - bootstrap.memory_lock=true 13 | - discovery.type=single-node 14 | - path.repo=/tmp 15 | - network.publish_host=127.0.0.1 16 | - logger.org.elasticsearch=warn 17 | - "ES_JAVA_OPTS=-Xms1g -Xmx1g" 18 | - ${OSS_ENV_VAR:-FOO=bar} 19 | command: ${ES_COMMAND} 20 | ulimits: 21 | nproc: 65536 22 | nofile: 23 | soft: 65536 24 | hard: 65536 25 | memlock: 26 | soft: -1 27 | hard: -1 28 | ports: 29 | - 9200:9200 30 | xpack: 31 | image: ${XPACK_IMAGE:-rwgrim/docker-noop} 32 | hostname: elasticsearch-xpack 33 | container_name: elasticsearch-xpack 34 | environment: 35 | - cluster.name=xpack 36 | - bootstrap.memory_lock=true 37 | - discovery.type=single-node 38 | - path.repo=/tmp 39 | - xpack.license.self_generated.type=trial 40 | - xpack.security.enabled=true 41 | - xpack.watcher.enabled=true 42 | - http.port=9210 43 | - network.publish_host=127.0.0.1 44 | - logger.org.elasticsearch=warn 45 | - "ES_JAVA_OPTS=-Xms1g -Xmx1g" 46 | - ELASTIC_PASSWORD=elastic 47 | ulimits: 48 | nproc: 65536 49 | nofile: 50 | soft: 65536 51 | hard: 65536 52 | memlock: 53 | soft: -1 54 | hard: -1 55 | ports: 56 | - 9210:9210 57 | opendistro: 58 | image: ${ES_OPENDISTRO_IMAGE:-rwgrim/docker-noop} 59 | hostname: elasticsearch-opendistro 60 | container_name: elasticsearch-opendistro 61 | environment: 62 | - cluster.name=opendistro 63 | - bootstrap.memory_lock=true 64 | - discovery.type=single-node 65 | - path.repo=/tmp 66 | - ${OPENSEARCH_PREFIX:-opendistro_security}.ssl.http.enabled=false 67 | - http.port=9220 68 | - network.publish_host=127.0.0.1 69 | - logger.org.elasticsearch=warn 70 | - "ES_JAVA_OPTS=-Xms1g -Xmx1g" 71 | ulimits: 72 | nproc: 65536 73 | nofile: 74 | soft: 65536 75 | hard: 65536 76 | memlock: 77 | soft: -1 78 | hard: -1 79 | ports: 80 | - 9220:9220 81 | xpack-kibana: 82 | image: ${XPACK_IMAGE:-rwgrim/docker-noop} 83 | networks: 84 | - elasticsearch # used by ESv7 kibana 85 | environment: 86 | - bootstrap.memory_lock=true 87 | - discovery.type=single-node 88 | - xpack.security.enabled=false 89 | - http.port=9230 90 | - logger.org.elasticsearch=warn 91 | - "ES_JAVA_OPTS=-Xms512m -Xmx512m" 92 | mem_limit: 1g 93 | ulimits: 94 | nproc: 65536 95 | nofile: 96 | soft: 65536 97 | hard: 65536 98 | memlock: 99 | soft: -1 100 | hard: -1 101 | ports: 102 | - 9230:9230 103 | kibana: 104 | image: ${ES_KIBANA_IMAGE:-rwgrim/docker-noop} 105 | networks: 106 | - elasticsearch 107 | links: 108 | - xpack-kibana 109 | environment: 110 | XPACK_ENCRYPTEDSAVEDOBJECTS_ENCRYPTIONKEY: aaaa1111bbbb2222cccc3333dddd4444 111 | ELASTICSEARCH_HOSTS: http://xpack-kibana:9230 112 | depends_on: 113 | - elasticsearch 114 | - xpack-kibana 115 | ulimits: 116 | nproc: 65536 117 | nofile: 118 | soft: 65536 119 | hard: 65536 120 | memlock: 121 | soft: -1 122 | hard: -1 123 | ports: 124 | - 5601:5601 125 | networks: 126 | elasticsearch: 127 | driver: bridge 128 | -------------------------------------------------------------------------------- /docs/data-sources/host.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "elasticsearch_host Data Source - terraform-provider-elasticsearch" 4 | subcategory: "" 5 | description: |- 6 | elasticsearch_host can be used to retrieve the host URL for the provider's current elasticsearch cluster. 7 | --- 8 | 9 | # elasticsearch_host (Data Source) 10 | 11 | `elasticsearch_host` can be used to retrieve the host URL for the provider's current elasticsearch cluster. 12 | 13 | ## Example Usage 14 | 15 | ```terraform 16 | data "elasticsearch_host" "test" { 17 | active = true 18 | } 19 | ``` 20 | 21 | 22 | ## Schema 23 | 24 | ### Required 25 | 26 | - **active** (Boolean) should be set to `true` 27 | 28 | ### Read-Only 29 | 30 | - **id** (String) The ID of this resource. 31 | - **url** (String) the url of the active elasticsearch cluster 32 | 33 | 34 | -------------------------------------------------------------------------------- /docs/data-sources/opensearch_destination.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_title: "elasticsearch_opensearch_destination Data Source - terraform-provider-elasticsearch" 3 | subcategory: "" 4 | description: |- 5 | elasticsearch_opensearch_destination can be used to retrieve the destination ID by name. 6 | --- 7 | 8 | # Data Source `elasticsearch_opensearch_destination` 9 | 10 | `elasticsearch_opensearch_destination` can be used to retrieve the destination ID by name. 11 | 12 | ## Example Usage 13 | 14 | ```terraform 15 | # Example destination in other terraform plan 16 | # resource "elasticsearch_opensearch_destination" "test" { 17 | # body = < 47 | ## Schema 48 | 49 | ### Required 50 | 51 | - `body` (String) The JSON body of the template. 52 | - `name` (String) Name of the component template to create. 53 | 54 | ### Read-Only 55 | 56 | - `id` (String) The ID of this resource. 57 | 58 | ## Import 59 | 60 | Import is supported using the following syntax: 61 | 62 | ```shell 63 | # Import by name 64 | terraform import elasticsearch_component_template.test terraform-test 65 | ``` 66 | -------------------------------------------------------------------------------- /docs/resources/composable_index_template.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "elasticsearch" 3 | page_title: "Elasticsearch: elasticsearch_composable_index_template" 4 | subcategory: "Elasticsearch Opensource" 5 | description: |- 6 | Provides an Elasticsearch Composable index template resource. 7 | --- 8 | 9 | # elasticsearch_composable_index_template 10 | 11 | Provides an Elasticsearch Composable index template resource. This resource uses the `/_index_template` 12 | endpoint of Elasticsearch API that is available since version 7.8. Use `elasticsearch_index_template` if 13 | you are using older versions of Elasticsearch or if you want to keep using legacy Index Templates in Elasticsearch 7.8+. 14 | 15 | ## Example Usage 16 | 17 | ```tf 18 | # Create an index template 19 | resource "elasticsearch_composable_index_template" "template_1" { 20 | name = "template_1" 21 | body = < 33 | ## Schema 34 | 35 | ### Required 36 | 37 | - **name** (String) Name of the data stream to create, must have a matching 38 | 39 | ### Read-Only 40 | 41 | - **id** (String) The ID of this resource. 42 | 43 | 44 | -------------------------------------------------------------------------------- /docs/resources/index_template.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "elasticsearch" 3 | page_title: "Elasticsearch: elasticsearch_index_template" 4 | subcategory: "Elasticsearch Opensource" 5 | description: |- 6 | Provides an Elasticsearch index template resource. 7 | --- 8 | 9 | # elasticsearch_index_template 10 | 11 | Provides an Elasticsearch index template resource. 12 | 13 | ## Example Usage 14 | 15 | ```tf 16 | # Create an index template 17 | resource "elasticsearch_index_template" "template_1" { 18 | name = "template_1" 19 | body = < 46 | ## Schema 47 | 48 | ### Required 49 | 50 | - **name** (String) The name of the alert, does not have to be unique, used to identify and find an alert. 51 | 52 | ### Optional 53 | 54 | - **actions** (Block Set) Actions are invocations of Kibana services or integrations with third-party systems, that run as background tasks on the Kibana server when alert conditions are met. (see [below for nested schema](#nestedblock--actions)) 55 | - **alert_type_id** (String) The ID of the alert type that you want to call when the alert is scheduled to run, defaults to `.index-threshold`. 56 | - **conditions** (Block Set, Max: 1) The conditions under which the alert is active, they create an expression to be evaluated by the alert type executor. These parameters are passed to the executor `params`. There may be specific attributes for different alert types. Either `params_json` or `conditions` must be specified. (see [below for nested schema](#nestedblock--conditions)) 57 | - **consumer** (String) The name of the application that owns the alert. This name has to match the Kibana Feature name, as that dictates the required RBAC privileges. Defaults to `alerts`. 58 | - **enabled** (Boolean) Whether the alert is scheduled for evaluation. 59 | - **notify_when** (String) The condition for throttling the notification: `onActionGroupChange`, `onActiveAlert`, or `onThrottleInterval`. Only available in Kibana >= 7.11 60 | - **params_json** (String) JSON body of alert `params`. Either `params_json` or `conditions` must be specified. 61 | - **schedule** (Block List, Max: 1) How frequently the alert conditions are checked. Note that the timing of evaluating alerts is not guaranteed, particularly for intervals of less than 10 seconds (see [below for nested schema](#nestedblock--schedule)) 62 | - **tags** (Set of String) A list of tag names, they appear in the alert listing in the UI which is searchable by tag. 63 | - **throttle** (String) How often this alert should fire the same action, this reduces repeated notifications. 64 | 65 | ### Read-Only 66 | 67 | - **id** (String) The ID of this resource. 68 | 69 | 70 | ### Nested Schema for `actions` 71 | 72 | Required: 73 | 74 | - **action_type_id** (String) The type of the action, e.g. `.index`, `.webhook`, etc. 75 | - **id** (String) The identifier of the saved action object, a UUID. 76 | 77 | Optional: 78 | 79 | - **group** (String) When to execute the action, e.g. `threshold met` or `recovered`. 80 | - **params** (Map of String) Key value pairs passed to the action executor, e.g. a Mustache formatted `message`. 81 | 82 | 83 | 84 | ### Nested Schema for `conditions` 85 | 86 | Required: 87 | 88 | - **index** (Set of String) 89 | - **threshold** (Set of Number) 90 | - **threshold_comparator** (String) 91 | - **time_field** (String) 92 | - **time_window_size** (Number) 93 | - **time_window_unit** (String) 94 | 95 | Optional: 96 | 97 | - **aggregation_field** (String) 98 | - **aggregation_type** (String) 99 | - **group_by** (String) 100 | - **term_field** (String) 101 | - **term_size** (Number) 102 | 103 | 104 | 105 | ### Nested Schema for `schedule` 106 | 107 | Required: 108 | 109 | - **interval** (String) Specifies the interval in seconds, minutes, hours or days at which the alert should execute, e.g. 10s, 5m, 1h. 110 | 111 | ## Import 112 | 113 | Import is supported using the following syntax: 114 | 115 | ```shell 116 | # Import by name 117 | terraform import elasticsearch_kibana_alert.test terraform-alert 118 | ``` 119 | -------------------------------------------------------------------------------- /docs/resources/kibana_object.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "elasticsearch" 3 | page_title: "Elasticsearch: elasticsearch_kibana_object" 4 | subcategory: "Elasticsearch Opensource" 5 | description: |- 6 | Provides an Elasticsearch kibana object resource. 7 | --- 8 | 9 | # elasticsearch_kibana_object 10 | 11 | Provides an Elasticsearch kibana object resource. This resource interacts directly with the underlying Elasticsearch index backing Kibana, so the format must match what Kibana the version of Kibana is expecting. Kibana v5 and v6 will export all objects in Kibana v5 format, so the exported objects cannot be used as a source for `body` in this resource - directly pulling the JSON from a Kibana index of the same version of Elasticsearch targeted by the provider is a workaround. 12 | 13 | With the removal of mapping types in Elasticsearch, the Kibana index changed from v5 to >= v6, previously the document mapping type had the Kibana object type, however, the `_type` going forward is `doc` and the type is within the document, see below. Using v5 doc types in v6 and above will result in errors from Elasticsearch after one or more document types are used. 14 | 15 | ## Example Usage 16 | 17 | ```tf 18 | resource "elasticsearch_kibana_object" "test_visualization_v6" { 19 | body = < 71 | ## Schema 72 | 73 | ### Required 74 | 75 | - **enabled** (Boolean) 76 | 77 | ### Optional 78 | 79 | - **audit** (Block Set) (see [below for nested schema](#nestedblock--audit)) 80 | - **compliance** (Block Set) (see [below for nested schema](#nestedblock--compliance)) 81 | - **id** (String) The ID of this resource. 82 | 83 | 84 | ### Nested Schema for `audit` 85 | 86 | Optional: 87 | 88 | - **disabled_rest_categories** (Set of String) 89 | - **disabled_transport_categories** (Set of String) 90 | - **enable_rest** (Boolean) 91 | - **enable_transport** (Boolean) 92 | - **exclude_sensitive_headers** (Boolean) 93 | - **ignore_requests** (Set of String) 94 | - **ignore_users** (Set of String) 95 | - **log_request_body** (Boolean) 96 | - **resolve_bulk_requests** (Boolean) 97 | - **resolve_indices** (Boolean) 98 | 99 | 100 | 101 | ### Nested Schema for `compliance` 102 | 103 | Optional: 104 | 105 | - **enabled** (Boolean) 106 | - **external_config** (Boolean) 107 | - **internal_config** (Boolean) 108 | - **read_ignore_users** (Set of String) 109 | - **read_metadata_only** (Boolean) 110 | - **read_watched_fields** (Map of Set of String) 111 | - **write_ignore_users** (Set of String) 112 | - **write_log_diffs** (Boolean) 113 | - **write_metadata_only** (Boolean) 114 | - **write_watched_indices** (Set of String) 115 | 116 | 117 | -------------------------------------------------------------------------------- /docs/resources/opensearch_destination.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "elasticsearch_opensearch_destination Resource - terraform-provider-elasticsearch" 4 | subcategory: "OpenSearch" 5 | description: |- 6 | Provides an OpenSearch destination, a reusable communication channel for an action, such as email, Slack, or a webhook URL. Please refer to the OpenSearch destination documentation https://opendistro.github.io/for-elasticsearch-docs/docs/alerting/monitors/#create-destinations for details. 7 | --- 8 | 9 | # elasticsearch_opensearch_destination (Resource) 10 | 11 | Provides an OpenSearch destination, a reusable communication channel for an action, such as email, Slack, or a webhook URL. Please refer to the OpenSearch [destination documentation](https://opendistro.github.io/for-elasticsearch-docs/docs/alerting/monitors/#create-destinations) for details. 12 | 13 | ## Example Usage 14 | 15 | ```terraform 16 | resource "elasticsearch_opensearch_destination" "test_destination" { 17 | body = < 30 | ## Schema 31 | 32 | ### Required 33 | 34 | - **body** (String) The JSON body of the destination. 35 | 36 | ### Read-Only 37 | 38 | - **id** (String) The ID of this resource. 39 | 40 | ## Import 41 | 42 | Import is supported using the following syntax: 43 | 44 | ```shell 45 | # Import by name 46 | terraform import elasticsearch_opensearch_destination.test_destination my-destination 47 | ``` 48 | -------------------------------------------------------------------------------- /docs/resources/opensearch_ism_policy.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "elasticsearch" 3 | page_title: "Elasticsearch: elasticsearch_opensearch_ism_policy" 4 | subcategory: "OpenSearch" 5 | description: |- 6 | Provides an Elasticsearch Open Distro ISM policy. 7 | --- 8 | 9 | # elasticsearch_opensearch_ism_policy 10 | 11 | Provides an OpenSearch ISM policy. 12 | Please refer to the Open Distro [ISM documentation][1] for details. 13 | 14 | ## Example Usage 15 | 16 | ```hcl 17 | # Create an ISM policy 18 | resource "elasticsearch_opensearch_ism_policy" "cleanup" { 19 | policy_id = "delete_after_15d" 20 | body = file("${path.module}/policies/delete_after_15d.json") 21 | } 22 | ``` 23 | 24 | ## Argument Reference 25 | 26 | The following arguments are supported: 27 | 28 | * `policy_id` - 29 | (Required) The id of the ISM policy. 30 | * `body` - 31 | (Required) The policy document. 32 | 33 | ## Attributes Reference 34 | 35 | The following attributes are exported: 36 | 37 | * `id` - 38 | The id of the ISM policy. 39 | * `primary_term` - 40 | The primary term of the ISM policy version. 41 | * `seq_no` - 42 | The sequence number of the ISM policy version. 43 | 44 | ## Import 45 | 46 | Elasticsearch Open Distro ISM policy can be imported using the `policy_id`, e.g. 47 | 48 | ```sh 49 | $ terraform import elasticsearch_opensearch_ism_policy.cleanup delete_after_15d 50 | ``` 51 | 52 | 53 | [1]: https://opendistro.github.io/for-elasticsearch-docs/docs/ism/ 54 | -------------------------------------------------------------------------------- /docs/resources/opensearch_ism_policy_mapping.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "elasticsearch_opensearch_ism_policy_mapping Resource - terraform-provider-elasticsearch" 4 | subcategory: "OpenSearch" 5 | description: |- 6 | Provides an OpenSearch Index State Management (ISM) policy. Please refer to the Open Distro ISM documentation https://opendistro.github.io/for-elasticsearch-docs/docs/ism/ for details. 7 | --- 8 | 9 | # elasticsearch_opensearch_ism_policy_mapping (Resource) 10 | 11 | Provides an OpenSearch Index State Management (ISM) policy. Please refer to the Open Distro [ISM documentation](https://opendistro.github.io/for-elasticsearch-docs/docs/ism/) for details. 12 | 13 | ## Example Usage 14 | 15 | ```terraform 16 | resource "elasticsearch_opensearch_ism_policy_mapping" "test" { 17 | policy_id = "policy_1" 18 | indexes = "test_index" 19 | state = "delete" 20 | } 21 | ``` 22 | 23 | 24 | ## Schema 25 | 26 | ### Required 27 | 28 | - **indexes** (String) Name of the index to apply the policy to. You can use an index pattern to update multiple indices at once. 29 | - **policy_id** (String) The name of the policy. 30 | 31 | ### Optional 32 | 33 | - **include** (Set of Map of String) When updating multiple indices, you might want to include a state filter to only affect certain managed indices. The background process only applies the change if the index is currently in the state specified. 34 | - **is_safe** (Boolean) 35 | - **managed_indexes** (Set of String) 36 | - **state** (String) After a change in policy takes place, specify the state for the index to transition to 37 | - **timeouts** (Block, Optional) (see [below for nested schema](#nestedblock--timeouts)) 38 | 39 | ### Read-Only 40 | 41 | - **id** (String) The ID of this resource. 42 | 43 | 44 | ### Nested Schema for `timeouts` 45 | 46 | Optional: 47 | 48 | - **create** (String) 49 | - **update** (String) 50 | 51 | ## Import 52 | 53 | Import is supported using the following syntax: 54 | 55 | ```shell 56 | # Import by poilcy_id 57 | terraform import elasticsearch_opensearch_ism_policy_mapping.test policy_1 58 | ``` 59 | -------------------------------------------------------------------------------- /docs/resources/opensearch_kibana_tenant.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "elasticsearch" 3 | page_title: "Elasticsearch: elasticsearch_opensearch_kibana_tenant" 4 | subcategory: "OpenSearch" 5 | description: |- 6 | Provides an Elasticsearch OpenSearch Kibana tenant resource. 7 | --- 8 | 9 | # elasticsearch_opensearch_kibana_tenant 10 | 11 | Provides an Elasticsearch OpenSearch Kibana tenant resource. 12 | Please refer to the OpenSearch [documentation][1] for details. 13 | 14 | ## Example Usage 15 | 16 | ```hcl 17 | # Create a tenant 18 | resource "elasticsearch_opensearch_kibana_tenant" "test" { 19 | tenant_name = "test" 20 | description = "test tenant" 21 | } 22 | ``` 23 | 24 | ## Argument Reference 25 | 26 | The following arguments are supported: 27 | 28 | * `tenant_name` - 29 | (Required) The name of the tenant. 30 | * `description` - 31 | (Optional) Description of the tenant. 32 | 33 | ## Attributes Reference 34 | 35 | The following attributes are exported: 36 | 37 | * `id` - 38 | The name of the tenant. 39 | 40 | ## Import 41 | 42 | Elasticsearch OpenSearch tenant can be imported using the `tenant_name`, e.g. 43 | 44 | ```sh 45 | $ terraform import elasticsearch_opensearch_kibana_tenant.writer test 46 | ``` 47 | 48 | 49 | [1]: https://opendistro.github.io/for-elasticsearch-docs/docs/security/access-control/multi-tenancy/ 50 | -------------------------------------------------------------------------------- /docs/resources/opensearch_monitor.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "elasticsearch" 3 | page_title: "Elasticsearch: elasticsearch_opensearch_monitor" 4 | subcategory: "OpenSearch" 5 | description: |- 6 | Provides an Elasticsearch OpenSearch monitor. 7 | --- 8 | 9 | # elasticsearch_opensearch_monitor 10 | 11 | Provides an Elasticsearch OpenSearch monitor. 12 | Please refer to the OpenSearch [monitor documentation][1] for details. 13 | 14 | ## Example Usage 15 | 16 | ```hcl 17 | # Create an monitor 18 | resource "elasticsearch_opensearch_monitor" "movies_last_hour" { 19 | body = < 0", 64 | "lang" : "painless" 65 | } 66 | }, 67 | "actions" : [ 68 | { 69 | "name" : "Slack", 70 | "destination_id" : "${elasticsearch_opensearch_destination.slack_on_call_channel.id}", 71 | "message_template" : { 72 | "source" : "bogus", 73 | "lang" : "mustache" 74 | }, 75 | "throttle_enabled" : false, 76 | "subject_template" : { 77 | "source" : "Production Errors", 78 | "lang" : "mustache" 79 | } 80 | } 81 | ] 82 | } 83 | ] 84 | } 85 | EOF 86 | } 87 | ``` 88 | 89 | ## Argument Reference 90 | 91 | The following arguments are supported: 92 | 93 | * `body` - 94 | (Required) The policy document. 95 | 96 | ## Attributes Reference 97 | 98 | The following attributes are exported: 99 | 100 | * `id` - 101 | The id of the monitor. 102 | 103 | ## Import 104 | 105 | Elasticsearch OpenSearch monitor can be imported using the `id`, e.g. 106 | 107 | ```sh 108 | $ terraform import elasticsearch_opensearch_monitor.alert lgOZb3UB96pyyRQv0ppQ 109 | ``` 110 | 111 | 112 | [1]: https://opendistro.github.io/for-elasticsearch-docs/docs/alerting/monitors/ 113 | -------------------------------------------------------------------------------- /docs/resources/opensearch_role.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "elasticsearch" 3 | page_title: "Elasticsearch: elasticsearch_opensearch_role" 4 | subcategory: "OpenSearch" 5 | description: |- 6 | Provides an Elasticsearch OpenSearch security role resource. 7 | --- 8 | 9 | # elasticsearch_opensearch_role 10 | 11 | Provides an Elasticsearch OpenSearch security role resource. 12 | Please refer to the OpenSearch [Access Control documentation][1] for details. 13 | 14 | ## Example Usage 15 | 16 | ```hcl 17 | # Create a role 18 | resource "elasticsearch_opensearch_role" "writer" { 19 | role_name = "logs_writer" 20 | description = "Logs writer role" 21 | 22 | cluster_permissions = ["*"] 23 | 24 | index_permissions { 25 | index_patterns = ["logstash-*"] 26 | allowed_actions = ["write"] 27 | } 28 | 29 | tenant_permissions { 30 | tenant_patterns = ["logstash-*"] 31 | allowed_actions = ["kibana_all_write"] 32 | } 33 | } 34 | ``` 35 | 36 | To set document level permissions: 37 | 38 | ```hcl 39 | resource "elasticsearch_opensearch_role" "writer" { 40 | role_name = "foo_writer" 41 | 42 | cluster_permissions = ["*"] 43 | 44 | index_permissions { 45 | index_patterns = ["pub*"] 46 | allowed_actions = ["read"] 47 | document_level_security = "{\"term\": { \"readable_by\": \"$${user.name}\"}}" 48 | } 49 | } 50 | ``` 51 | 52 | 53 | ## Argument Reference 54 | 55 | The following arguments are supported: 56 | 57 | * `role_name` - 58 | (Required) The name of the security role. 59 | * `description` - 60 | (Optional) Description of the role. 61 | * `cluster_permissions` - 62 | (Optional) A list of cluster permissions. 63 | * `index_permissions` - 64 | (Optional) A configuration of index permissions (documented below). 65 | * `tenant_permissions` - 66 | (Optional) A configuration of tenant permissions (documented below). 67 | 68 | The `index_permissions` object supports the following: 69 | 70 | * `index_patterns` - 71 | (Optional) A list of glob patterns for the index names. 72 | * `document_level_security` - 73 | (Optional) A selector for [document-level security][2] (json formatted using jsonencode). 74 | * `field_level_security` - 75 | (Optional) A list of selectors for [field-level security][3]. 76 | * `masked_fields` - 77 | (Optional) A list of [masked fields][4]. 78 | * `allowed_actions` - 79 | (Optional) A list of allowed actions. 80 | 81 | The `tenant_permissions` object supports the following: 82 | 83 | * `tenant_patterns` - 84 | (Optional) A list of glob patterns for the [tenant][5] names. 85 | * `allowed_actions` - 86 | (Optional) A list of allowed actions. 87 | 88 | ## Attributes Reference 89 | 90 | The following attributes are exported: 91 | 92 | * `id` - 93 | The name of the security role. 94 | 95 | ## Import 96 | 97 | Elasticsearch OpenSearch security role can be imported using the `role_name`, e.g. 98 | 99 | ```sh 100 | $ terraform import elasticsearch_opensearch_role.writer logs_writer 101 | ``` 102 | 103 | 104 | [1]: https://opendistro.github.io/for-elasticsearch-docs/docs/security/access-control/ 105 | [1]: https://opendistro.github.io/for-elasticsearch-docs/docs/security/access-control/document-level-security/ 106 | [3]: https://opendistro.github.io/for-elasticsearch-docs/docs/security/access-control/field-level-security/ 107 | [4]: https://opendistro.github.io/for-elasticsearch-docs/docs/security/access-control/field-masking/ 108 | [5]: https://opendistro.github.io/for-elasticsearch-docs/docs/security/access-control/multi-tenancy/ 109 | -------------------------------------------------------------------------------- /docs/resources/opensearch_roles_mapping.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "elasticsearch" 3 | page_title: "Elasticsearch: elasticsearch_opensearch_roles_mapping" 4 | subcategory: "OpenSearch" 5 | description: |- 6 | Provides an Elasticsearch OpenSearch security role mapping. 7 | --- 8 | 9 | # elasticsearch_opensearch_roles_mapping 10 | 11 | Provides an Elasticsearch OpenSearch security role mapping. 12 | Please refer to the OpenSearch [Access Control documentation][1] for details. 13 | 14 | ## Example Usage 15 | 16 | ```hcl 17 | # Create a role mapping 18 | resource "elasticsearch_opensearch_roles_mapping" "mapper" { 19 | role_name = "logs_writer" 20 | description = "Mapping AWS IAM roles to ES role" 21 | backend_roles = [ 22 | "arn:aws:iam::123456789012:role/lambda-call-elasticsearch", 23 | "arn:aws:iam::123456789012:role/run-containers", 24 | ] 25 | } 26 | ``` 27 | 28 | ## Argument Reference 29 | 30 | The following arguments are supported: 31 | 32 | * `role_name` - 33 | (Required) The name of the security role. 34 | * `description` - 35 | (Optional) Description of the role mapping. 36 | * `backend_roles` - 37 | (Optional) A list of backend roles. 38 | * `hosts` - 39 | (Optional) A list of host names. 40 | * `users` - 41 | (Optional) A list of users. 42 | * `and_backend_roles` - 43 | (Optional) A list of backend roles. 44 | 45 | ## Attributes Reference 46 | 47 | The following attributes are exported: 48 | 49 | * `id` - 50 | The name of the security role. 51 | 52 | ## Import 53 | 54 | Elasticsearch OpenSearch security role mapping can be imported using the `role_name`, e.g. 55 | 56 | ```sh 57 | $ terraform import elasticsearch_opensearch_roles_mapping.mapper logs_writer 58 | ``` 59 | 60 | 61 | [1]: https://opendistro.github.io/for-elasticsearch-docs/docs/security/access-control/ 62 | -------------------------------------------------------------------------------- /docs/resources/opensearch_user.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "elasticsearch" 3 | page_title: "Elasticsearch: elasticsearch_opensearch_user" 4 | subcategory: "OpenSearch" 5 | description: |- 6 | Provides an Elasticsearch OpenSearch security user. 7 | --- 8 | 9 | # elasticsearch_opensearch_user 10 | 11 | Provides an Elasticsearch OpenSearch security user. Please refer to the OpenSearch [Access Control documentation][1] for details. 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | # Create a user 17 | resource "elasticsearch_opensearch_user" "mapper" { 18 | username = "app-reader" 19 | password = "SuperSekret123!" 20 | description = "a reader role for our app" 21 | } 22 | ``` 23 | 24 | And a full user, role and role mapping example: 25 | 26 | ```hcl 27 | resource "elasticsearch_opensearch_role" "reader" { 28 | role_name = "app_reader" 29 | description = "App Reader Role" 30 | 31 | index_permissions { 32 | index_patterns = ["app-*"] 33 | allowed_actions = ["get", "read", "search"] 34 | } 35 | } 36 | 37 | resource "elasticsearch_opensearch_user" "reader" { 38 | username = "app-reader" 39 | password = var.password 40 | } 41 | 42 | resource "elasticsearch_opensearch_roles_mapping" "reader" { 43 | role_name = elasticsearch_opensearch_role.reader.id 44 | description = "App Reader Role" 45 | users = [elasticsearch_opensearch_user.reader.id] 46 | } 47 | ``` 48 | 49 | ## Argument Reference 50 | 51 | The following arguments are supported: 52 | 53 | * `username` - 54 | (Required) The name of the security role. 55 | * `description` - 56 | (Optional) Description of the user. 57 | * `backend_roles` - 58 | (Optional) A list of backend roles. 59 | * `password` - 60 | (Optional) The plain text password for the user, cannot be specified with `password_hash`. 61 | Some implementations may enforce a password policy. Invalid passwords may cause a non-descriptive 62 | HTTP 400 Bad Request error. For AWS Elasticsearch domains "password must be at least 8 characters 63 | long and contain at least one uppercase letter, one lowercase letter, one digit, and one special 64 | character". 65 | * `password_hash` - 66 | (Optional) The pre-hashed password for the user, cannot be specified with `password`. 67 | * `attributes` - 68 | (Optional) A map of arbitrary key value string pairs stored alongside of users. 69 | 70 | ## Attributes Reference 71 | 72 | The following attributes are exported: 73 | 74 | * `id` - 75 | The name of the security user. 76 | 77 | ## Import 78 | 79 | Elasticsearch OpenSearch user can be imported using the `username`, e.g. 80 | 81 | ```sh 82 | $ terraform import elasticsearch_opensearch_user.reader app_reader 83 | ``` 84 | 85 | 86 | [1]: https://opendistro.github.io/for-elasticsearch-docs/docs/security/access-control/ 87 | -------------------------------------------------------------------------------- /docs/resources/script.md: -------------------------------------------------------------------------------- 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. 37 | 38 | ## Import 39 | 40 | Scripts can be imported using the `script_id`, e.g. 41 | 42 | ```sh 43 | $ terraform import elasticsearch_script.test_script my_script 44 | ``` 45 | -------------------------------------------------------------------------------- /docs/resources/snapshot_repository.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "elasticsearch" 3 | page_title: "Elasticsearch: elasticsearch_snapshot_repository" 4 | subcategory: "Elasticsearch Opensource" 5 | description: |- 6 | Provides an Elasticsearch snapshot repository resource. 7 | --- 8 | 9 | # elasticsearch_snapshot_repository 10 | 11 | Provides an Elasticsearch snapshot repository resource. 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | # Create a snapshot repository 17 | resource "elasticsearch_snapshot_repository" "repo" { 18 | name = "es-index-backups" 19 | type = "s3" 20 | settings = { 21 | bucket = "es-index-backups" 22 | region = "us-east-1" 23 | role_arn = "arn:aws:iam::123456789012:role/MyElasticsearchRole" 24 | } 25 | } 26 | ``` 27 | 28 | ## Argument Reference 29 | 30 | The following arguments are supported: 31 | 32 | * `name` - (Required) The name of the repository. 33 | * `type` - (Required) The name of the repository backend (required plugins must be installed). 34 | * `settings` - (Optional) The settings map applicable for the backend (documented [here](https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-snapshots.html) for official plugins). 35 | 36 | ## Attributes Reference 37 | 38 | The following attributes are exported: 39 | 40 | * `id` - The name of the snapshot repository. 41 | 42 | ## Import 43 | 44 | Snapshot repositories can be imported using the `name`, e.g. 45 | 46 | ```sh 47 | $ terraform import elasticsearch_snapshot_repository.repo es-index-backups 48 | ``` 49 | -------------------------------------------------------------------------------- /docs/resources/xpack_index_lifecycle_policy.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "elasticsearch" 3 | page_title: "Elasticsearch: elasticsearch_xpack_index_lifecycle_policy" 4 | subcategory: "Elasticsearch Xpack" 5 | description: |- 6 | Provides an Elasticsearch XPack index lifecycle policy resource. 7 | --- 8 | 9 | # elasticsearch_xpack_index_lifecycle_policy 10 | 11 | Provides an Elasticsearch XPack index lifecycle policy resource. Please see [docs](https://www.elastic.co/guide/en/elasticsearch/reference/current/index-lifecycle-management-api.html) for more details on usage. 12 | 13 | ## Example Usage 14 | 15 | ```tf 16 | # Create an xpack index_lifecycle_policy 17 | resource "elasticsearch_xpack_index_lifecycle_policy" "test" { 18 | name = "terraform-test" 19 | body = < 43 | ## Schema 44 | 45 | ### Required 46 | 47 | - **role_mapping_name** (String) The distinct name that identifies the role mapping, used solely as an identifier. 48 | - **roles** (Set of String) A list of role names that are granted to the users that match the role mapping rules. 49 | - **rules** (String) A list of mustache templates that will be evaluated to determine the roles names that should granted to the users that match the role mapping rules. This matches fields of users, rules can be grouped into `all` and `any` top level keys. 50 | 51 | ### Optional 52 | 53 | - **enabled** (Boolean) Mappings that have `enabled` set to `false` are ignored when role mapping is performed. 54 | - **metadata** (String) Additional metadata that helps define which roles are assigned to each user. Keys beginning with `_` are reserved for system usage. 55 | 56 | ### Read-Only 57 | 58 | - **id** (String) The ID of this resource. 59 | 60 | ## Import 61 | 62 | Import is supported using the following syntax: 63 | 64 | ```shell 65 | # Import by name 66 | terraform import elasticsearch_xpack_role_mapping.test test 67 | ``` 68 | -------------------------------------------------------------------------------- /docs/resources/xpack_snapshot_lifecycle_policy.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "elasticsearch_xpack_snapshot_lifecycle_policy Resource - terraform-provider-elasticsearch" 4 | subcategory: "Elasticsearch Xpack" 5 | description: |- 6 | Provides an Elasticsearch XPack snapshot lifecycle management policy. These automatically take snapshots and control how long they are retained. See the upstream docs https://www.elastic.co/guide/en/elasticsearch/reference/current/snapshot-lifecycle-management-api.html for more details. 7 | --- 8 | 9 | # elasticsearch_xpack_snapshot_lifecycle_policy (Resource) 10 | 11 | Provides an Elasticsearch XPack snapshot lifecycle management policy. These automatically take snapshots and control how long they are retained. See the upstream [docs](https://www.elastic.co/guide/en/elasticsearch/reference/current/snapshot-lifecycle-management-api.html) for more details. 12 | 13 | ## Example Usage 14 | 15 | ```terraform 16 | resource "elasticsearch_xpack_snapshot_lifecycle_policy" "terraform-test" { 17 | name = "test" 18 | body = <", 22 | "repository": "terraform-test", 23 | "config": { 24 | "indices": ["data-*", "important"], 25 | "ignore_unavailable": false, 26 | "include_global_state": false 27 | }, 28 | "retention": { 29 | "expire_after": "30d", 30 | "min_count": 5, 31 | "max_count": 50 32 | } 33 | } 34 | EOF 35 | } 36 | ``` 37 | 38 | 39 | ## Schema 40 | 41 | ### Required 42 | 43 | - **body** (String) See the policy definition defined in the [docs](https://www.elastic.co/guide/en/elasticsearch/reference/current/slm-api-put-policy.html#slm-api-put-request-body) 44 | - **name** (String) ID for the snapshot lifecycle policy 45 | 46 | ### Read-Only 47 | 48 | - **id** (String) The ID of this resource. 49 | 50 | ## Import 51 | 52 | Import is supported using the following syntax: 53 | 54 | ```shell 55 | # Import by name 56 | terraform import elasticsearch_xpack_snapshot_lifecycle_policy.terraform-test test 57 | ``` 58 | -------------------------------------------------------------------------------- /docs/resources/xpack_user.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "elasticsearch_xpack_user Resource - terraform-provider-elasticsearch" 4 | subcategory: "Elasticsearch Xpack" 5 | description: |- 6 | Provides an Elasticsearch XPack user resource. See the upstream docs https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api.html for more details. 7 | --- 8 | 9 | # elasticsearch_xpack_user (Resource) 10 | 11 | Provides an Elasticsearch XPack user resource. See the upstream [docs](https://www.elastic.co/guide/en/elasticsearch/reference/current/security-api.html) for more details. 12 | 13 | ## Example Usage 14 | 15 | ```terraform 16 | resource "elasticsearch_xpack_user" "test" { 17 | username = "johndoe" 18 | fullname = "John DoDo" 19 | email = "john@do.com" 20 | password = "secret" 21 | roles = ["admin"] 22 | metadata = <<-EOF 23 | { 24 | "foo": "bar" 25 | } 26 | EOF 27 | } 28 | ``` 29 | 30 | 31 | ## Schema 32 | 33 | ### Required 34 | 35 | - **roles** (Set of String) A set of roles the user has. The roles determine the user’s access permissions 36 | - **username** (String) An identifier for the user. 37 | 38 | Usernames must be at least 1 and no more than 1024 characters. They can contain alphanumeric characters (a-z, A-Z, 0-9), spaces, punctuation, and printable symbols in the Basic Latin (ASCII) block. Leading or trailing whitespace is not allowed. 39 | 40 | ### Optional 41 | 42 | - **email** (String) The email of the user 43 | - **enabled** (Boolean) Specifies whether the user is enabled, defaults to true. 44 | - **fullname** (String) The full name of the user 45 | - **metadata** (String) Arbitrary metadata that you want to associate with the user 46 | - **password** (String, Sensitive) The user’s password. Passwords must be at least 6 characters long. Mutually exclusive with `password_hash`, one of which must be provided at creation. 47 | - **password_hash** (String, Sensitive) A hash of the user’s password. This must be produced using the same hashing algorithm as has been configured for password storage. Mutually exclusive with `password`, one of which must be provided at creation. 48 | 49 | ### Read-Only 50 | 51 | - **id** (String) The ID of this resource. 52 | 53 | ## Import 54 | 55 | Import is supported using the following syntax: 56 | 57 | ```shell 58 | # Import by username 59 | terraform import elasticsearch_xpack_user.test johndoe 60 | ``` 61 | -------------------------------------------------------------------------------- /docs/resources/xpack_watch.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "elasticsearch" 3 | page_title: "Elasticsearch: elasticsearch_xpack_watch" 4 | subcategory: "Elasticsearch Xpack" 5 | description: |- 6 | Provides an Elasticsearch XPack watch resource. 7 | --- 8 | 9 | # elasticsearch_xpack_watch 10 | 11 | Provides an Elasticsearch XPack watch resource. 12 | 13 | ## Example Usage 14 | 15 | ```tf 16 | # Create an xpack watch 17 | resource "elasticsearch_xpack_watch" "watch_1" { 18 | watch_id = "watch_1" 19 | active = true 20 | body = < 0 { 49 | url = urls.Index(0).String() 50 | } 51 | case *elastic6.Client: 52 | urls := reflect.ValueOf(client).Elem().FieldByName("urls") 53 | if urls.Len() > 0 { 54 | url = urls.Index(0).String() 55 | } 56 | default: 57 | return errors.New("this version of Elasticsearch is not supported") 58 | } 59 | d.SetId(url) 60 | err = d.Set("url", url) 61 | 62 | return err 63 | } 64 | -------------------------------------------------------------------------------- /es/data_source_elasticsearch_host_test.go: -------------------------------------------------------------------------------- 1 | package es 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 8 | ) 9 | 10 | func TestAccElasticsearchDataSourceHost_basic(t *testing.T) { 11 | var providers []*schema.Provider 12 | resource.ParallelTest(t, resource.TestCase{ 13 | PreCheck: func() { 14 | testAccPreCheck(t) 15 | }, 16 | ProviderFactories: testAccProviderFactories(&providers), 17 | Steps: []resource.TestStep{ 18 | { 19 | Config: testAccElasticsearchDataSourceHost, 20 | Check: resource.ComposeAggregateTestCheckFunc( 21 | resource.TestCheckResourceAttrSet("data.elasticsearch_host.test", "id"), 22 | resource.TestCheckResourceAttrSet("data.elasticsearch_host.test", "url"), 23 | ), 24 | }, 25 | }, 26 | }) 27 | } 28 | 29 | var testAccElasticsearchDataSourceHost = ` 30 | data "elasticsearch_host" "test" { 31 | active = true 32 | } 33 | ` 34 | -------------------------------------------------------------------------------- /es/data_source_elasticsearch_opendistro_destination_test.go: -------------------------------------------------------------------------------- 1 | package es 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 7 | ) 8 | 9 | func TestAccElasticsearchDataSourceDestination_basic(t *testing.T) { 10 | resource.ParallelTest(t, resource.TestCase{ 11 | PreCheck: func() { 12 | testAccPreCheck(t) 13 | }, 14 | Providers: testAccOpendistroProviders, 15 | Steps: []resource.TestStep{ 16 | { 17 | Config: testAccElasticsearchDataSourceDestination, 18 | Check: resource.ComposeAggregateTestCheckFunc( 19 | resource.TestCheckResourceAttrSet("data.elasticsearch_opendistro_destination.test", "id"), 20 | resource.TestCheckResourceAttrSet("data.elasticsearch_opendistro_destination.test", "body.type"), 21 | ), 22 | }, 23 | }, 24 | }) 25 | } 26 | 27 | var testAccElasticsearchDataSourceDestination = ` 28 | resource "elasticsearch_opendistro_destination" "test" { 29 | body = <= 7.8) Index template definition 32 | For legacy index templates (ES < 7.8) or /_template endpoint on ES >= 7.8 see diffSuppressIndexTemplate. 33 | */ 34 | func diffSuppressComposableIndexTemplate(k, old, new string, d *schema.ResourceData) bool { 35 | var oo, no interface{} 36 | if err := json.Unmarshal([]byte(old), &oo); err != nil { 37 | return false 38 | } 39 | if err := json.Unmarshal([]byte(new), &no); err != nil { 40 | return false 41 | } 42 | 43 | if om, ok := oo.(map[string]interface{}); ok { 44 | normalizeComposableIndexTemplate(om) 45 | } 46 | 47 | if nm, ok := no.(map[string]interface{}); ok { 48 | normalizeComposableIndexTemplate(nm) 49 | } 50 | 51 | return reflect.DeepEqual(oo, no) 52 | } 53 | 54 | func diffSuppressComponentTemplate(k, old, new string, d *schema.ResourceData) bool { 55 | var oo, no interface{} 56 | if err := json.Unmarshal([]byte(old), &oo); err != nil { 57 | return false 58 | } 59 | if err := json.Unmarshal([]byte(new), &no); err != nil { 60 | return false 61 | } 62 | 63 | if om, ok := oo.(map[string]interface{}); ok { 64 | normalizeComponentTemplate(om) 65 | } 66 | 67 | if nm, ok := no.(map[string]interface{}); ok { 68 | normalizeComponentTemplate(nm) 69 | } 70 | 71 | return reflect.DeepEqual(oo, no) 72 | } 73 | 74 | func diffSuppressDestination(k, old, new string, d *schema.ResourceData) bool { 75 | var oo, no interface{} 76 | if err := json.Unmarshal([]byte(old), &oo); err != nil { 77 | return false 78 | } 79 | if err := json.Unmarshal([]byte(new), &no); err != nil { 80 | return false 81 | } 82 | 83 | if om, ok := oo.(map[string]interface{}); ok { 84 | normalizeDestination(om) 85 | } 86 | 87 | if nm, ok := no.(map[string]interface{}); ok { 88 | normalizeDestination(nm) 89 | } 90 | 91 | return reflect.DeepEqual(oo, no) 92 | } 93 | 94 | func diffSuppressMonitor(k, old, new string, d *schema.ResourceData) bool { 95 | var oo, no interface{} 96 | if err := json.Unmarshal([]byte(old), &oo); err != nil { 97 | return false 98 | } 99 | if err := json.Unmarshal([]byte(new), &no); err != nil { 100 | return false 101 | } 102 | 103 | if om, ok := oo.(map[string]interface{}); ok { 104 | normalizeMonitor(om) 105 | } 106 | 107 | if nm, ok := no.(map[string]interface{}); ok { 108 | normalizeMonitor(nm) 109 | } 110 | 111 | return reflect.DeepEqual(oo, no) 112 | } 113 | 114 | func suppressEquivalentJson(k, old, new string, d *schema.ResourceData) bool { 115 | var oldObj, newObj interface{} 116 | if err := json.Unmarshal([]byte(old), &oldObj); err != nil { 117 | return false 118 | } 119 | if err := json.Unmarshal([]byte(new), &newObj); err != nil { 120 | return false 121 | } 122 | return reflect.DeepEqual(oldObj, newObj) 123 | } 124 | 125 | func diffSuppressIndexLifecyclePolicy(k, old, new string, d *schema.ResourceData) bool { 126 | var oo, no interface{} 127 | if err := json.Unmarshal([]byte(old), &oo); err != nil { 128 | return false 129 | } 130 | if err := json.Unmarshal([]byte(new), &no); err != nil { 131 | return false 132 | } 133 | 134 | if om, ok := oo.(map[string]interface{}); ok { 135 | normalizeIndexLifecyclePolicy(om) 136 | } 137 | 138 | if nm, ok := no.(map[string]interface{}); ok { 139 | normalizeIndexLifecyclePolicy(nm) 140 | } 141 | 142 | return reflect.DeepEqual(oo, no) 143 | } 144 | 145 | func diffSuppressSnapshotLifecyclePolicy(k, old, new string, d *schema.ResourceData) bool { 146 | var oo, no interface{} 147 | if err := json.Unmarshal([]byte(old), &oo); err != nil { 148 | return false 149 | } 150 | if err := json.Unmarshal([]byte(new), &no); err != nil { 151 | return false 152 | } 153 | 154 | if om, ok := oo.(map[string]interface{}); ok { 155 | normalizeSnapshotLifecyclePolicy(om) 156 | } 157 | 158 | if nm, ok := no.(map[string]interface{}); ok { 159 | normalizeSnapshotLifecyclePolicy(nm) 160 | } 161 | 162 | return reflect.DeepEqual(oo, no) 163 | } 164 | 165 | func diffSuppressIngestPipeline(k, old, new string, d *schema.ResourceData) bool { 166 | var oo, no interface{} 167 | if err := json.Unmarshal([]byte(old), &oo); err != nil { 168 | return false 169 | } 170 | if err := json.Unmarshal([]byte(new), &no); err != nil { 171 | return false 172 | } 173 | 174 | return reflect.DeepEqual(oo, no) 175 | } 176 | 177 | func diffSuppressPolicy(k, old, new string, d *schema.ResourceData) bool { 178 | var oo, no interface{} 179 | if err := json.Unmarshal([]byte(old), &oo); err != nil { 180 | return false 181 | } 182 | if err := json.Unmarshal([]byte(new), &no); err != nil { 183 | return false 184 | } 185 | 186 | if om, ok := oo.(map[string]interface{}); ok { 187 | normalizePolicy(om) 188 | } 189 | 190 | if nm, ok := no.(map[string]interface{}); ok { 191 | normalizePolicy(nm) 192 | } 193 | 194 | return reflect.DeepEqual(oo, no) 195 | } 196 | 197 | func diffSuppressLicense(k, old, new string, d *schema.ResourceData) bool { 198 | var oldObj, newObj map[string]interface{} 199 | if err := json.Unmarshal([]byte(old), &oldObj); err != nil { 200 | return false 201 | } 202 | if err := json.Unmarshal([]byte(new), &newObj); err != nil { 203 | return false 204 | } 205 | return reflect.DeepEqual(oldObj, newObj) 206 | } 207 | -------------------------------------------------------------------------------- /es/http.go: -------------------------------------------------------------------------------- 1 | package es 2 | 3 | import ( 4 | "net/http" 5 | ) 6 | 7 | type withHeader struct { 8 | http.Header 9 | hostOverride string 10 | rt http.RoundTripper 11 | } 12 | 13 | func WithHeader(rt http.RoundTripper) withHeader { 14 | if rt == nil { 15 | rt = http.DefaultTransport 16 | } 17 | 18 | return withHeader{Header: make(http.Header), rt: rt} 19 | } 20 | 21 | func (h withHeader) RoundTrip(req *http.Request) (*http.Response, error) { 22 | for k, v := range h.Header { 23 | req.Header[k] = v 24 | } 25 | if h.hostOverride != "" { 26 | req.Host = h.hostOverride 27 | } 28 | 29 | return h.rt.RoundTrip(req) 30 | } 31 | -------------------------------------------------------------------------------- /es/resource_elasticsearch_cluster_settings_test.go: -------------------------------------------------------------------------------- 1 | package es 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "testing" 7 | 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 9 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" 10 | ) 11 | 12 | func TestAccElasticsearchClusterSettings(t *testing.T) { 13 | resource.Test(t, resource.TestCase{ 14 | PreCheck: func() { testAccPreCheck(t) }, 15 | Providers: testAccProviders, 16 | CheckDestroy: checkElasticsearchClusterSettingsDestroy, 17 | Steps: []resource.TestStep{ 18 | { 19 | Config: testAccElasticsearchClusterSettings, 20 | Check: resource.ComposeTestCheckFunc( 21 | testCheckElasticsearchClusterSettingInState("elasticsearch_cluster_settings.global"), 22 | testCheckElasticsearchClusterSettingExists("action.auto_create_index"), 23 | ), 24 | }, 25 | }, 26 | }) 27 | } 28 | 29 | func testCheckElasticsearchClusterSettingInState(name string) resource.TestCheckFunc { 30 | return func(s *terraform.State) error { 31 | rs, ok := s.RootModule().Resources[name] 32 | if !ok { 33 | return fmt.Errorf("not found: %s", name) 34 | } 35 | if rs.Primary.ID == "" { 36 | return fmt.Errorf("cluster ID not set") 37 | } 38 | 39 | return nil 40 | } 41 | } 42 | 43 | func testCheckElasticsearchClusterSettingExists(name string) resource.TestCheckFunc { 44 | return func(s *terraform.State) error { 45 | meta := testAccProvider.Meta() 46 | settings, err := resourceElasticsearchClusterSettingsGet(meta) 47 | if err != nil { 48 | return err 49 | } 50 | 51 | persistentSettings := settings["persistent"].(map[string]interface{}) 52 | _, ok := persistentSettings[name] 53 | if !ok { 54 | return fmt.Errorf("%s not found in settings, found %+v", name, persistentSettings) 55 | } 56 | 57 | return nil 58 | } 59 | } 60 | 61 | func checkElasticsearchClusterSettingsDestroy(s *terraform.State) error { 62 | for _, rs := range s.RootModule().Resources { 63 | if rs.Type != "elasticsearch_cluster_settings" { 64 | continue 65 | } 66 | 67 | meta := testAccProvider.Meta() 68 | settings, err := resourceElasticsearchClusterSettingsGet(meta) 69 | if err != nil { 70 | return err 71 | } 72 | 73 | persistentSettings := settings["persistent"].(map[string]interface{}) 74 | if len(persistentSettings) != 0 { 75 | log.Printf("[INFO] checkElasticsearchClusterSettingsDestroy: %+v", persistentSettings) 76 | return fmt.Errorf("%d cluster settings still exist", len(persistentSettings)) 77 | } 78 | 79 | return nil 80 | } 81 | 82 | return nil 83 | } 84 | 85 | var testAccElasticsearchClusterSettings = ` 86 | resource "elasticsearch_cluster_settings" "global" { 87 | cluster_max_shards_per_node = 10 88 | action_auto_create_index = "my-index-000001,index10,-index1*,+ind*" 89 | } 90 | ` 91 | -------------------------------------------------------------------------------- /es/resource_elasticsearch_component_template_test.go: -------------------------------------------------------------------------------- 1 | package es 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "testing" 8 | 9 | elastic7 "github.com/olivere/elastic/v7" 10 | 11 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 12 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" 13 | ) 14 | 15 | func TestAccElasticsearchComponentTemplate(t *testing.T) { 16 | provider := Provider() 17 | diags := provider.Configure(context.Background(), &terraform.ResourceConfig{}) 18 | if diags.HasError() { 19 | t.Skipf("err: %#v", diags) 20 | } 21 | meta := provider.Meta() 22 | 23 | esClient, err := getClient(meta.(*ProviderConf)) 24 | if err != nil { 25 | t.Skipf("err: %s", err) 26 | } 27 | 28 | var allowed bool 29 | switch esClient.(type) { 30 | case *elastic7.Client: 31 | allowed = true 32 | default: 33 | allowed = false 34 | } 35 | resource.Test(t, resource.TestCase{ 36 | PreCheck: func() { 37 | testAccPreCheck(t) 38 | if !allowed { 39 | t.Skip("/_component_template endpoint only supported on ES >= 7.8") 40 | } 41 | }, 42 | Providers: testAccProviders, 43 | CheckDestroy: testCheckElasticsearchComponentTemplateDestroy, 44 | Steps: []resource.TestStep{ 45 | { 46 | Config: testAccElasticsearchComponentTemplate, 47 | Check: resource.ComposeTestCheckFunc( 48 | testCheckElasticsearchComponentTemplateExists("elasticsearch_component_template.test"), 49 | ), 50 | }, 51 | }, 52 | }) 53 | } 54 | 55 | func TestAccElasticsearchComponentTemplate_importBasic(t *testing.T) { 56 | provider := Provider() 57 | diags := provider.Configure(context.Background(), &terraform.ResourceConfig{}) 58 | if diags.HasError() { 59 | t.Skipf("err: %#v", diags) 60 | } 61 | meta := provider.Meta() 62 | 63 | esClient, err := getClient(meta.(*ProviderConf)) 64 | if err != nil { 65 | t.Skipf("err: %s", err) 66 | } 67 | 68 | var allowed bool 69 | switch esClient.(type) { 70 | case *elastic7.Client: 71 | allowed = true 72 | default: 73 | allowed = false 74 | } 75 | resource.Test(t, resource.TestCase{ 76 | PreCheck: func() { 77 | testAccPreCheck(t) 78 | if !allowed { 79 | t.Skip("/_component_template endpoint only supported on ES >= 7.8") 80 | } 81 | }, 82 | Providers: testAccProviders, 83 | CheckDestroy: testCheckElasticsearchComponentTemplateDestroy, 84 | Steps: []resource.TestStep{ 85 | { 86 | Config: testAccElasticsearchComponentTemplate, 87 | }, 88 | { 89 | ResourceName: "elasticsearch_component_template.test", 90 | ImportState: true, 91 | ImportStateVerify: true, 92 | }, 93 | }, 94 | }) 95 | } 96 | 97 | func testCheckElasticsearchComponentTemplateExists(name string) resource.TestCheckFunc { 98 | return func(s *terraform.State) error { 99 | rs, ok := s.RootModule().Resources[name] 100 | if !ok { 101 | return fmt.Errorf("Not found: %s", name) 102 | } 103 | if rs.Primary.ID == "" { 104 | return fmt.Errorf("No component template ID is set") 105 | } 106 | 107 | meta := testAccProvider.Meta() 108 | 109 | esClient, err := getClient(meta.(*ProviderConf)) 110 | if err != nil { 111 | return err 112 | } 113 | 114 | switch client := esClient.(type) { 115 | case *elastic7.Client: 116 | _, err = client.IndexGetComponentTemplate(rs.Primary.ID).Do(context.TODO()) 117 | default: 118 | err = errors.New("/_component_template endpoint only supported on ES >= 7.8") 119 | } 120 | 121 | if err != nil { 122 | return err 123 | } 124 | 125 | return nil 126 | } 127 | } 128 | 129 | func testCheckElasticsearchComponentTemplateDestroy(s *terraform.State) error { 130 | for _, rs := range s.RootModule().Resources { 131 | if rs.Type != "elasticsearch_component_template" { 132 | continue 133 | } 134 | 135 | meta := testAccProvider.Meta() 136 | 137 | esClient, err := getClient(meta.(*ProviderConf)) 138 | if err != nil { 139 | return err 140 | } 141 | 142 | switch client := esClient.(type) { 143 | case *elastic7.Client: 144 | _, err = client.IndexGetComponentTemplate(rs.Primary.ID).Do(context.TODO()) 145 | default: 146 | err = errors.New("/_component_template endpoint only supported on ES >= 7.8") 147 | } 148 | 149 | if err != nil { 150 | return nil // should be not found error 151 | } 152 | 153 | return fmt.Errorf("Component template %q still exists", rs.Primary.ID) 154 | } 155 | 156 | return nil 157 | } 158 | 159 | var testAccElasticsearchComponentTemplate = ` 160 | resource "elasticsearch_component_template" "test" { 161 | name = "terraform-test" 162 | body = <= 7.8, got version %s", elasticVersion.String()) 75 | } 76 | } 77 | default: 78 | err = fmt.Errorf("index_template endpoint only available from ElasticSearch >= 7.8, got version < 7.0.0") 79 | } 80 | if err != nil { 81 | if elastic7.IsNotFound(err) { 82 | log.Printf("[WARN] Index template (%s) not found, removing from state", id) 83 | d.SetId("") 84 | return nil 85 | } 86 | 87 | return err 88 | } 89 | 90 | ds := &resourceDataSetter{d: d} 91 | ds.set("name", d.Id()) 92 | ds.set("body", result) 93 | return ds.err 94 | } 95 | 96 | func elastic7GetIndexTemplate(client *elastic7.Client, id string) (string, error) { 97 | res, err := client.IndexGetIndexTemplate(id).Do(context.TODO()) 98 | log.Printf("[INFO] Index template %+v %+v", res, err) 99 | if err != nil { 100 | return "", err 101 | } 102 | 103 | // No more than 1 element is expected, if the index template is not found, previous call should 104 | // return a 404 error 105 | t := res.IndexTemplates[0].IndexTemplate 106 | tj, err := json.Marshal(t) 107 | if err != nil { 108 | return "", err 109 | } 110 | return string(tj), nil 111 | } 112 | 113 | func resourceElasticsearchComposableIndexTemplateUpdate(d *schema.ResourceData, meta interface{}) error { 114 | return resourceElasticsearchPutComposableIndexTemplate(d, meta, false) 115 | } 116 | 117 | func resourceElasticsearchComposableIndexTemplateDelete(d *schema.ResourceData, meta interface{}) error { 118 | id := d.Id() 119 | 120 | var elasticVersion *version.Version 121 | 122 | providerConf := meta.(*ProviderConf) 123 | esClient, err := getClient(providerConf) 124 | if err != nil { 125 | return err 126 | } 127 | 128 | switch client := esClient.(type) { 129 | case *elastic7.Client: 130 | elasticVersion, err = version.NewVersion(providerConf.esVersion) 131 | if err == nil { 132 | if resourceElasticsearchComposableIndexTemplateAvailable(elasticVersion, providerConf) { 133 | err = elastic7DeleteIndexTemplate(client, id) 134 | } else { 135 | err = fmt.Errorf("index_template endpoint only available from ElasticSearch >= 7.8, got version %s", elasticVersion.String()) 136 | } 137 | } 138 | default: 139 | err = fmt.Errorf("index_template endpoint only available from ElasticSearch >= 7.8, got version < 7.0.0") 140 | } 141 | 142 | if err != nil { 143 | return err 144 | } 145 | d.SetId("") 146 | return nil 147 | } 148 | 149 | func elastic7DeleteIndexTemplate(client *elastic7.Client, id string) error { 150 | _, err := client.IndexDeleteIndexTemplate(id).Do(context.TODO()) 151 | return err 152 | } 153 | 154 | func resourceElasticsearchPutComposableIndexTemplate(d *schema.ResourceData, meta interface{}, create bool) error { 155 | name := d.Get("name").(string) 156 | body := d.Get("body").(string) 157 | 158 | var elasticVersion *version.Version 159 | 160 | providerConf := meta.(*ProviderConf) 161 | esClient, err := getClient(providerConf) 162 | if err != nil { 163 | return err 164 | } 165 | 166 | switch client := esClient.(type) { 167 | case *elastic7.Client: 168 | elasticVersion, err = version.NewVersion(providerConf.esVersion) 169 | if err == nil { 170 | if resourceElasticsearchComposableIndexTemplateAvailable(elasticVersion, providerConf) { 171 | err = elastic7PutIndexTemplate(client, name, body, create) 172 | } else { 173 | err = fmt.Errorf("index_template endpoint only available from ElasticSearch >= 7.8, got version %s", elasticVersion.String()) 174 | } 175 | } 176 | default: 177 | err = fmt.Errorf("index_template endpoint only available from ElasticSearch >= 7.8, got version < 7.0.0") 178 | } 179 | 180 | return err 181 | } 182 | 183 | func elastic7PutIndexTemplate(client *elastic7.Client, name string, body string, create bool) error { 184 | _, err := client.IndexPutIndexTemplate(name).BodyString(body).Create(create).Do(context.TODO()) 185 | return err 186 | } 187 | -------------------------------------------------------------------------------- /es/resource_elasticsearch_composable_index_template_test.go: -------------------------------------------------------------------------------- 1 | package es 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "testing" 8 | 9 | elastic7 "github.com/olivere/elastic/v7" 10 | 11 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 12 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" 13 | ) 14 | 15 | func TestAccElasticsearchComposableIndexTemplate(t *testing.T) { 16 | provider := Provider() 17 | diags := provider.Configure(context.Background(), &terraform.ResourceConfig{}) 18 | if diags.HasError() { 19 | t.Skipf("err: %#v", diags) 20 | } 21 | meta := provider.Meta() 22 | 23 | esClient, err := getClient(meta.(*ProviderConf)) 24 | if err != nil { 25 | t.Skipf("err: %s", err) 26 | } 27 | 28 | var allowed bool 29 | switch esClient.(type) { 30 | case *elastic7.Client: 31 | allowed = true 32 | default: 33 | allowed = false 34 | } 35 | resource.Test(t, resource.TestCase{ 36 | PreCheck: func() { 37 | testAccPreCheck(t) 38 | if !allowed { 39 | t.Skip("/_index_template endpoint only supported on ES >= 7.8") 40 | } 41 | }, 42 | Providers: testAccProviders, 43 | CheckDestroy: testCheckElasticsearchComposableIndexTemplateDestroy, 44 | Steps: []resource.TestStep{ 45 | { 46 | Config: testAccElasticsearchComposableIndexTemplate, 47 | Check: resource.ComposeTestCheckFunc( 48 | testCheckElasticsearchComposableIndexTemplateExists("elasticsearch_composable_index_template.test"), 49 | ), 50 | }, 51 | }, 52 | }) 53 | } 54 | 55 | func TestAccElasticsearchComposableIndexTemplate_importBasic(t *testing.T) { 56 | provider := Provider() 57 | diags := provider.Configure(context.Background(), &terraform.ResourceConfig{}) 58 | if diags.HasError() { 59 | t.Skipf("err: %#v", diags) 60 | } 61 | meta := provider.Meta() 62 | 63 | esClient, err := getClient(meta.(*ProviderConf)) 64 | if err != nil { 65 | t.Skipf("err: %s", err) 66 | } 67 | 68 | var allowed bool 69 | switch esClient.(type) { 70 | case *elastic7.Client: 71 | allowed = true 72 | default: 73 | allowed = false 74 | } 75 | resource.Test(t, resource.TestCase{ 76 | PreCheck: func() { 77 | testAccPreCheck(t) 78 | if !allowed { 79 | t.Skip("/_index_template endpoint only supported on ES >= 7.8") 80 | } 81 | }, 82 | Providers: testAccProviders, 83 | CheckDestroy: testCheckElasticsearchComposableIndexTemplateDestroy, 84 | Steps: []resource.TestStep{ 85 | { 86 | Config: testAccElasticsearchComposableIndexTemplate, 87 | }, 88 | { 89 | ResourceName: "elasticsearch_composable_index_template.test", 90 | ImportState: true, 91 | ImportStateVerify: true, 92 | }, 93 | }, 94 | }) 95 | } 96 | 97 | func testCheckElasticsearchComposableIndexTemplateExists(name string) resource.TestCheckFunc { 98 | return func(s *terraform.State) error { 99 | rs, ok := s.RootModule().Resources[name] 100 | if !ok { 101 | return fmt.Errorf("Not found: %s", name) 102 | } 103 | if rs.Primary.ID == "" { 104 | return fmt.Errorf("No index template ID is set") 105 | } 106 | 107 | meta := testAccProvider.Meta() 108 | 109 | esClient, err := getClient(meta.(*ProviderConf)) 110 | if err != nil { 111 | return err 112 | } 113 | 114 | switch client := esClient.(type) { 115 | case *elastic7.Client: 116 | _, err = client.IndexGetIndexTemplate(rs.Primary.ID).Do(context.TODO()) 117 | default: 118 | err = errors.New("/_index_template endpoint only supported on ES >= 7.8") 119 | } 120 | 121 | if err != nil { 122 | return err 123 | } 124 | 125 | return nil 126 | } 127 | } 128 | 129 | func testCheckElasticsearchComposableIndexTemplateDestroy(s *terraform.State) error { 130 | for _, rs := range s.RootModule().Resources { 131 | if rs.Type != "elasticsearch_composable_index_template" { 132 | continue 133 | } 134 | 135 | meta := testAccProvider.Meta() 136 | 137 | esClient, err := getClient(meta.(*ProviderConf)) 138 | if err != nil { 139 | return err 140 | } 141 | 142 | switch client := esClient.(type) { 143 | case *elastic7.Client: 144 | _, err = client.IndexGetIndexTemplate(rs.Primary.ID).Do(context.TODO()) 145 | default: 146 | err = errors.New("/_index_template endpoint only supported on ES >= 7.8") 147 | } 148 | 149 | if err != nil { 150 | return nil // should be not found error 151 | } 152 | 153 | return fmt.Errorf("Index template %q still exists", rs.Primary.ID) 154 | } 155 | 156 | return nil 157 | } 158 | 159 | var testAccElasticsearchComposableIndexTemplate = ` 160 | resource "elasticsearch_composable_index_template" "test" { 161 | name = "terraform-test" 162 | body = <= 7.9, got version %s", elasticVersion.String()) 70 | } 71 | } 72 | default: 73 | err = fmt.Errorf("_data_stream endpoint only available from ElasticSearch >= 7.9, got version < 7.0.0") 74 | } 75 | if err != nil { 76 | if elastic7.IsNotFound(err) { 77 | log.Printf("[WARN] data stream (%s) not found, removing from state", id) 78 | d.SetId("") 79 | return nil 80 | } 81 | 82 | return err 83 | } 84 | 85 | ds := &resourceDataSetter{d: d} 86 | ds.set("name", d.Id()) 87 | return ds.err 88 | } 89 | 90 | func resourceElasticsearchDataStreamDelete(d *schema.ResourceData, meta interface{}) error { 91 | id := d.Id() 92 | 93 | var elasticVersion *version.Version 94 | 95 | providerConf := meta.(*ProviderConf) 96 | esClient, err := getClient(providerConf) 97 | if err != nil { 98 | return err 99 | } 100 | 101 | switch client := esClient.(type) { 102 | case *elastic7.Client: 103 | elasticVersion, err = version.NewVersion(providerConf.esVersion) 104 | if err == nil { 105 | if resourceElasticsearchDataStreamAvailable(elasticVersion, providerConf) { 106 | err = elastic7DeleteDataStream(client, id) 107 | } else { 108 | err = fmt.Errorf("_data_stream endpoint only available from ElasticSearch >= 7.9, got version %s", elasticVersion.String()) 109 | } 110 | } 111 | default: 112 | err = fmt.Errorf("_data_stream endpoint only available from ElasticSearch >= 7.9, got version < 7.0.0") 113 | } 114 | 115 | if err != nil { 116 | return err 117 | } 118 | d.SetId("") 119 | return nil 120 | } 121 | 122 | func resourceElasticsearchPutDataStream(d *schema.ResourceData, meta interface{}) error { 123 | name := d.Get("name").(string) 124 | 125 | var elasticVersion *version.Version 126 | 127 | providerConf := meta.(*ProviderConf) 128 | esClient, err := getClient(providerConf) 129 | if err != nil { 130 | return err 131 | } 132 | 133 | switch client := esClient.(type) { 134 | case *elastic7.Client: 135 | elasticVersion, err = version.NewVersion(providerConf.esVersion) 136 | if err == nil { 137 | if resourceElasticsearchDataStreamAvailable(elasticVersion, providerConf) { 138 | err = elastic7PutDataStream(client, name) 139 | } else { 140 | err = fmt.Errorf("_data_stream endpoint only available from ElasticSearch >= 7.9, got version %s", elasticVersion.String()) 141 | } 142 | } 143 | default: 144 | err = fmt.Errorf("_data_stream endpoint only available from ElasticSearch >= 7.9, got version < 7.0.0") 145 | } 146 | 147 | return err 148 | } 149 | 150 | func elastic7GetDataStream(client *elastic7.Client, id string) error { 151 | path, err := uritemplates.Expand("/_data_stream/{id}", map[string]string{ 152 | "id": id, 153 | }) 154 | if err != nil { 155 | return fmt.Errorf("error building URL path for data stream: %+v", err) 156 | } 157 | 158 | _, err = client.PerformRequest(context.TODO(), elastic7.PerformRequestOptions{ 159 | Method: "GET", 160 | Path: path, 161 | }) 162 | return err 163 | } 164 | 165 | func elastic7DeleteDataStream(client *elastic7.Client, id string) error { 166 | path, err := uritemplates.Expand("/_data_stream/{id}", map[string]string{ 167 | "id": id, 168 | }) 169 | if err != nil { 170 | return fmt.Errorf("error building URL path for data stream: %+v", err) 171 | } 172 | 173 | _, err = client.PerformRequest(context.TODO(), elastic7.PerformRequestOptions{ 174 | Method: "DELETE", 175 | Path: path, 176 | }) 177 | return err 178 | } 179 | 180 | func elastic7PutDataStream(client *elastic7.Client, id string) error { 181 | path, err := uritemplates.Expand("/_data_stream/{id}", map[string]string{ 182 | "id": id, 183 | }) 184 | if err != nil { 185 | return fmt.Errorf("error building URL path for data stream: %+v", err) 186 | } 187 | 188 | _, err = client.PerformRequest(context.TODO(), elastic7.PerformRequestOptions{ 189 | Method: "PUT", 190 | Path: path, 191 | }) 192 | return err 193 | } 194 | -------------------------------------------------------------------------------- /es/resource_elasticsearch_data_stream_test.go: -------------------------------------------------------------------------------- 1 | package es 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "testing" 8 | 9 | elastic7 "github.com/olivere/elastic/v7" 10 | 11 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 12 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" 13 | ) 14 | 15 | func TestAccElasticsearchDataStream(t *testing.T) { 16 | provider := Provider() 17 | diags := provider.Configure(context.Background(), &terraform.ResourceConfig{}) 18 | if diags.HasError() { 19 | t.Skipf("err: %#v", diags) 20 | } 21 | meta := provider.Meta() 22 | 23 | esClient, err := getClient(meta.(*ProviderConf)) 24 | if err != nil { 25 | t.Skipf("err: %s", err) 26 | } 27 | 28 | var allowed bool 29 | switch esClient.(type) { 30 | case *elastic7.Client: 31 | allowed = true 32 | default: 33 | allowed = false 34 | } 35 | 36 | resource.Test(t, resource.TestCase{ 37 | PreCheck: func() { 38 | testAccPreCheck(t) 39 | 40 | if !allowed { 41 | t.Skip("/_data_stream endpoint only supported on ES >= 7.9") 42 | } 43 | }, 44 | Providers: testAccProviders, 45 | CheckDestroy: testCheckElasticsearchDataStreamDestroy, 46 | Steps: []resource.TestStep{ 47 | { 48 | Config: testAccElasticsearchDataStream, 49 | Check: resource.ComposeTestCheckFunc( 50 | testCheckElasticsearchDataStreamExists("elasticsearch_data_stream.foo"), 51 | ), 52 | }, 53 | }, 54 | }) 55 | } 56 | 57 | func testCheckElasticsearchDataStreamExists(name string) resource.TestCheckFunc { 58 | return func(s *terraform.State) error { 59 | rs, ok := s.RootModule().Resources[name] 60 | if !ok { 61 | return fmt.Errorf("Not found: %s", name) 62 | } 63 | if rs.Primary.ID == "" { 64 | return fmt.Errorf("No data stream ID is set") 65 | } 66 | 67 | meta := testAccProvider.Meta() 68 | 69 | var err error 70 | esClient, err := getClient(meta.(*ProviderConf)) 71 | if err != nil { 72 | return err 73 | } 74 | switch client := esClient.(type) { 75 | case *elastic7.Client: 76 | err = elastic7GetDataStream(client, rs.Primary.ID) 77 | default: 78 | return errors.New("Elasticsearch version not supported") 79 | } 80 | 81 | if err != nil { 82 | return err 83 | } 84 | 85 | return nil 86 | } 87 | } 88 | 89 | func testCheckElasticsearchDataStreamDestroy(s *terraform.State) error { 90 | for _, rs := range s.RootModule().Resources { 91 | if rs.Type != "elasticsearch_data_stream" { 92 | continue 93 | } 94 | 95 | meta := testAccProvider.Meta() 96 | 97 | var err error 98 | esClient, err := getClient(meta.(*ProviderConf)) 99 | if err != nil { 100 | return err 101 | } 102 | switch client := esClient.(type) { 103 | case *elastic7.Client: 104 | err = elastic7GetDataStream(client, rs.Primary.ID) 105 | default: 106 | return errors.New("Elasticsearch version not supported") 107 | } 108 | 109 | if err != nil { 110 | return nil // should be not found error 111 | } 112 | 113 | return fmt.Errorf("Data stream %q still exists", rs.Primary.ID) 114 | } 115 | 116 | return nil 117 | } 118 | 119 | var testAccElasticsearchDataStream = ` 120 | resource "elasticsearch_composable_index_template" "foo" { 121 | name = "foo-template" 122 | body = <= 7") 42 | } 43 | }, 44 | Providers: testAccOpendistroProviders, 45 | CheckDestroy: testAccCheckElasticsearchOpenDistroKibanaTenantDestroy, 46 | Steps: []resource.TestStep{ 47 | { 48 | Config: testAccOpenDistroKibanaTenantResource(randomName), 49 | Check: resource.ComposeTestCheckFunc( 50 | testCheckElasticSearchOpenDistroKibanaTenantExists("elasticsearch_opendistro_kibana_tenant.test"), 51 | resource.TestCheckResourceAttr( 52 | "elasticsearch_opendistro_kibana_tenant.test", 53 | "id", 54 | randomName, 55 | ), 56 | resource.TestCheckResourceAttr( 57 | "elasticsearch_opendistro_kibana_tenant.test", 58 | "description", 59 | "test", 60 | ), 61 | ), 62 | }, 63 | { 64 | Config: testAccOpenDistroKibanaTenantResourceUpdated(randomName), 65 | Check: resource.ComposeTestCheckFunc( 66 | testCheckElasticSearchOpenDistroKibanaTenantExists("elasticsearch_opendistro_kibana_tenant.test"), 67 | resource.TestCheckResourceAttr( 68 | "elasticsearch_opendistro_kibana_tenant.test", 69 | "description", 70 | "test2", 71 | ), 72 | ), 73 | }, 74 | }, 75 | }) 76 | } 77 | 78 | func testAccCheckElasticsearchOpenDistroKibanaTenantDestroy(s *terraform.State) error { 79 | for _, rs := range s.RootModule().Resources { 80 | if rs.Type != "elasticsearch_opendistro_kibana_tenant" { 81 | continue 82 | } 83 | 84 | meta := testAccOpendistroProvider.Meta() 85 | 86 | var err error 87 | esClient, err := getClient(meta.(*ProviderConf)) 88 | if err != nil { 89 | return err 90 | } 91 | switch esClient.(type) { 92 | case *elastic7.Client: 93 | _, err = resourceElasticsearchGetOpenDistroKibanaTenant(rs.Primary.ID, meta.(*ProviderConf)) 94 | default: 95 | } 96 | 97 | if err != nil { 98 | return nil // should be not found error 99 | } 100 | 101 | return fmt.Errorf("KibanaTenant %q still exists", rs.Primary.ID) 102 | } 103 | 104 | return nil 105 | } 106 | func testCheckElasticSearchOpenDistroKibanaTenantExists(name string) resource.TestCheckFunc { 107 | return func(s *terraform.State) error { 108 | for _, rs := range s.RootModule().Resources { 109 | if rs.Type != "elasticsearch_opendistro_kibana_tenant" { 110 | continue 111 | } 112 | 113 | meta := testAccOpendistroProvider.Meta() 114 | 115 | var err error 116 | esClient, err := getClient(meta.(*ProviderConf)) 117 | if err != nil { 118 | return err 119 | } 120 | switch esClient.(type) { 121 | case *elastic7.Client: 122 | _, err = resourceElasticsearchGetOpenDistroKibanaTenant(rs.Primary.ID, meta.(*ProviderConf)) 123 | default: 124 | } 125 | 126 | if err != nil { 127 | return err 128 | } 129 | 130 | return nil 131 | } 132 | 133 | return nil 134 | } 135 | } 136 | 137 | func testAccOpenDistroKibanaTenantResource(resourceName string) string { 138 | return fmt.Sprintf(` 139 | resource "elasticsearch_opendistro_kibana_tenant" "test" { 140 | tenant_name = "%s" 141 | description = "test" 142 | } 143 | `, resourceName) 144 | } 145 | 146 | func testAccOpenDistroKibanaTenantResourceUpdated(resourceName string) string { 147 | return fmt.Sprintf(` 148 | resource "elasticsearch_opendistro_kibana_tenant" "test" { 149 | tenant_name = "%s" 150 | description = "test2" 151 | } 152 | `, resourceName) 153 | } 154 | -------------------------------------------------------------------------------- /es/resource_elasticsearch_opendistro_roles_mapping_test.go: -------------------------------------------------------------------------------- 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/acctest" 12 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 13 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" 14 | ) 15 | 16 | func TestAccElasticsearchOpenDistroRolesMapping(t *testing.T) { 17 | provider := Provider() 18 | diags := provider.Configure(context.Background(), &terraform.ResourceConfig{}) 19 | if diags.HasError() { 20 | t.Skipf("err: %#v", diags) 21 | } 22 | meta := provider.Meta() 23 | var allowed bool 24 | esClient, err := getClient(meta.(*ProviderConf)) 25 | if err != nil { 26 | t.Skipf("err: %s", err) 27 | } 28 | switch esClient.(type) { 29 | case *elastic6.Client: 30 | allowed = false 31 | default: 32 | allowed = true 33 | } 34 | 35 | randomName := "test" + acctest.RandStringFromCharSet(10, acctest.CharSetAlpha) 36 | 37 | resource.ParallelTest(t, resource.TestCase{ 38 | PreCheck: func() { 39 | testAccPreCheck(t) 40 | if !allowed { 41 | t.Skip("Roles only supported on ES >= 7") 42 | } 43 | }, 44 | Providers: testAccOpendistroProviders, 45 | CheckDestroy: testAccCheckElasticsearchOpenDistroRolesMappingDestroy, 46 | Steps: []resource.TestStep{ 47 | { 48 | Config: testAccOpenDistroRolesMappingResource(randomName), 49 | Check: resource.ComposeTestCheckFunc( 50 | testCheckElasticSearchOpenDistroRolesMappingExists("elasticsearch_opendistro_roles_mapping.test"), 51 | resource.TestCheckResourceAttr( 52 | "elasticsearch_opendistro_roles_mapping.test", 53 | "id", 54 | "readall", 55 | ), 56 | resource.TestCheckResourceAttr( 57 | "elasticsearch_opendistro_roles_mapping.test", 58 | "backend_roles.#", 59 | "1", 60 | ), 61 | resource.TestCheckResourceAttr( 62 | "elasticsearch_opendistro_roles_mapping.test", 63 | "description", 64 | randomName, 65 | ), 66 | ), 67 | }, 68 | { 69 | Config: testAccOpenDistroRoleMappingResourceUpdated(randomName), 70 | Check: resource.ComposeTestCheckFunc( 71 | testCheckElasticSearchOpenDistroRolesMappingExists("elasticsearch_opendistro_roles_mapping.test"), 72 | resource.TestCheckResourceAttr( 73 | "elasticsearch_opendistro_roles_mapping.test", 74 | "backend_roles.#", 75 | "2", 76 | ), 77 | ), 78 | }, 79 | }, 80 | }) 81 | } 82 | 83 | func testAccCheckElasticsearchOpenDistroRolesMappingDestroy(s *terraform.State) error { 84 | for _, rs := range s.RootModule().Resources { 85 | if rs.Type != "elasticsearch_opendistro_roles_mappings_mapping" { 86 | continue 87 | } 88 | 89 | meta := testAccOpendistroProvider.Meta() 90 | 91 | var err error 92 | esClient, err := getClient(meta.(*ProviderConf)) 93 | if err != nil { 94 | return err 95 | } 96 | switch esClient.(type) { 97 | case *elastic7.Client: 98 | _, err = resourceElasticsearchGetOpenDistroRolesMapping(rs.Primary.ID, meta.(*ProviderConf)) 99 | default: 100 | } 101 | 102 | if err != nil { 103 | return nil // should be not found error 104 | } 105 | 106 | return fmt.Errorf("Role %q still exists", rs.Primary.ID) 107 | } 108 | 109 | return nil 110 | } 111 | func testCheckElasticSearchOpenDistroRolesMappingExists(name string) resource.TestCheckFunc { 112 | return func(s *terraform.State) error { 113 | for _, rs := range s.RootModule().Resources { 114 | if rs.Type != "elasticsearch_opendistro_roles_mapping" { 115 | continue 116 | } 117 | 118 | meta := testAccOpendistroProvider.Meta() 119 | 120 | var err error 121 | esClient, err := getClient(meta.(*ProviderConf)) 122 | if err != nil { 123 | return err 124 | } 125 | switch esClient.(type) { 126 | case *elastic7.Client: 127 | _, err = resourceElasticsearchGetOpenDistroRolesMapping(rs.Primary.ID, meta.(*ProviderConf)) 128 | default: 129 | } 130 | 131 | if err != nil { 132 | return err 133 | } 134 | 135 | return nil 136 | } 137 | 138 | return nil 139 | } 140 | } 141 | 142 | func testAccOpenDistroRolesMappingResource(resourceName string) string { 143 | return fmt.Sprintf(` 144 | resource "elasticsearch_opendistro_roles_mapping" "test" { 145 | role_name = "readall" 146 | backend_roles = [ 147 | "active_directory", 148 | ] 149 | 150 | description = "%s" 151 | } 152 | `, resourceName) 153 | } 154 | 155 | func testAccOpenDistroRoleMappingResourceUpdated(resourceName string) string { 156 | return fmt.Sprintf(` 157 | resource "elasticsearch_opendistro_roles_mapping" "test" { 158 | role_name = "readall" 159 | backend_roles = [ 160 | "active_directory", 161 | "ldap", 162 | ] 163 | 164 | description = "%s update" 165 | } 166 | `, resourceName) 167 | } 168 | -------------------------------------------------------------------------------- /es/resource_elasticsearch_script.go: -------------------------------------------------------------------------------- 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 | } 221 | -------------------------------------------------------------------------------- /es/resource_elasticsearch_script_test.go: -------------------------------------------------------------------------------- 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 | ` 104 | -------------------------------------------------------------------------------- /es/resource_elasticsearch_snapshot_repository.go: -------------------------------------------------------------------------------- 1 | package es 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 8 | elastic7 "github.com/olivere/elastic/v7" 9 | elastic6 "gopkg.in/olivere/elastic.v6" 10 | ) 11 | 12 | func resourceElasticsearchSnapshotRepository() *schema.Resource { 13 | return &schema.Resource{ 14 | Create: resourceElasticsearchSnapshotRepositoryCreate, 15 | Read: resourceElasticsearchSnapshotRepositoryRead, 16 | Update: resourceElasticsearchSnapshotRepositoryUpdate, 17 | Delete: resourceElasticsearchSnapshotRepositoryDelete, 18 | Schema: map[string]*schema.Schema{ 19 | "name": { 20 | Type: schema.TypeString, 21 | ForceNew: true, 22 | Required: true, 23 | }, 24 | "type": { 25 | Type: schema.TypeString, 26 | Required: true, 27 | }, 28 | "settings": { 29 | Type: schema.TypeMap, 30 | Optional: true, 31 | }, 32 | }, 33 | Importer: &schema.ResourceImporter{ 34 | StateContext: schema.ImportStatePassthroughContext, 35 | }, 36 | } 37 | } 38 | 39 | func resourceElasticsearchSnapshotRepositoryCreate(d *schema.ResourceData, meta interface{}) error { 40 | err := resourceElasticsearchSnapshotRepositoryUpdate(d, meta) 41 | if err != nil { 42 | return err 43 | } 44 | d.SetId(d.Get("name").(string)) 45 | return nil 46 | } 47 | 48 | func resourceElasticsearchSnapshotRepositoryRead(d *schema.ResourceData, meta interface{}) error { 49 | id := d.Id() 50 | 51 | var repositoryType string 52 | var settings map[string]interface{} 53 | var err error 54 | esClient, err := getClient(meta.(*ProviderConf)) 55 | if err != nil { 56 | return err 57 | } 58 | switch client := esClient.(type) { 59 | case *elastic7.Client: 60 | repositoryType, settings, err = elastic7SnapshotGetRepository(client, id) 61 | case *elastic6.Client: 62 | repositoryType, settings, err = elastic6SnapshotGetRepository(client, id) 63 | default: 64 | return errors.New("Elasticsearch version not supported") 65 | } 66 | 67 | if err != nil { 68 | return err 69 | } 70 | 71 | ds := &resourceDataSetter{d: d} 72 | ds.set("name", id) 73 | ds.set("type", repositoryType) 74 | ds.set("settings", settings) 75 | return ds.err 76 | } 77 | 78 | func elastic7SnapshotGetRepository(client *elastic7.Client, id string) (string, map[string]interface{}, error) { 79 | repos, err := client.SnapshotGetRepository(id).Do(context.TODO()) 80 | if err != nil { 81 | return "", make(map[string]interface{}), err 82 | } 83 | 84 | return repos[id].Type, repos[id].Settings, nil 85 | } 86 | 87 | func elastic6SnapshotGetRepository(client *elastic6.Client, id string) (string, map[string]interface{}, error) { 88 | repos, err := client.SnapshotGetRepository(id).Do(context.TODO()) 89 | if err != nil { 90 | return "", make(map[string]interface{}), err 91 | } 92 | 93 | return repos[id].Type, repos[id].Settings, nil 94 | } 95 | 96 | func resourceElasticsearchSnapshotRepositoryUpdate(d *schema.ResourceData, meta interface{}) error { 97 | repositoryType := d.Get("type").(string) 98 | name := d.Get("name").(string) 99 | 100 | var settings map[string]interface{} 101 | 102 | if v, ok := d.GetOk("settings"); ok { 103 | settings = v.(map[string]interface{}) 104 | } 105 | 106 | var err error 107 | esClient, err := getClient(meta.(*ProviderConf)) 108 | if err != nil { 109 | return err 110 | } 111 | switch client := esClient.(type) { 112 | case *elastic7.Client: 113 | err = elastic7SnapshotCreateRepository(client, name, repositoryType, settings) 114 | case *elastic6.Client: 115 | err = elastic6SnapshotCreateRepository(client, name, repositoryType, settings) 116 | default: 117 | return errors.New("Elasticsearch version not supported") 118 | } 119 | 120 | return err 121 | } 122 | 123 | func elastic7SnapshotCreateRepository(client *elastic7.Client, name string, repositoryType string, settings map[string]interface{}) error { 124 | repo := elastic7.SnapshotRepositoryMetaData{ 125 | Type: repositoryType, 126 | Settings: settings, 127 | } 128 | 129 | _, err := client.SnapshotCreateRepository(name).BodyJson(&repo).Do(context.TODO()) 130 | return err 131 | } 132 | 133 | func elastic6SnapshotCreateRepository(client *elastic6.Client, name string, repositoryType string, settings map[string]interface{}) error { 134 | repo := elastic6.SnapshotRepositoryMetaData{ 135 | Type: repositoryType, 136 | Settings: settings, 137 | } 138 | 139 | _, err := client.SnapshotCreateRepository(name).BodyJson(&repo).Do(context.TODO()) 140 | return err 141 | } 142 | 143 | func resourceElasticsearchSnapshotRepositoryDelete(d *schema.ResourceData, meta interface{}) error { 144 | id := d.Id() 145 | 146 | var err error 147 | esClient, err := getClient(meta.(*ProviderConf)) 148 | if err != nil { 149 | return err 150 | } 151 | switch client := esClient.(type) { 152 | case *elastic7.Client: 153 | err = elastic7SnapshotDeleteRepository(client, id) 154 | case *elastic6.Client: 155 | err = elastic6SnapshotDeleteRepository(client, id) 156 | default: 157 | return errors.New("Elasticsearch version not supported") 158 | } 159 | 160 | if err != nil { 161 | return err 162 | } 163 | d.SetId("") 164 | return nil 165 | } 166 | 167 | func elastic7SnapshotDeleteRepository(client *elastic7.Client, id string) error { 168 | _, err := client.SnapshotDeleteRepository(id).Do(context.TODO()) 169 | return err 170 | } 171 | 172 | func elastic6SnapshotDeleteRepository(client *elastic6.Client, id string) error { 173 | _, err := client.SnapshotDeleteRepository(id).Do(context.TODO()) 174 | return err 175 | } 176 | -------------------------------------------------------------------------------- /es/resource_elasticsearch_snapshot_repository_test.go: -------------------------------------------------------------------------------- 1 | package es 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "testing" 8 | 9 | elastic7 "github.com/olivere/elastic/v7" 10 | elastic6 "gopkg.in/olivere/elastic.v6" 11 | 12 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 13 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" 14 | ) 15 | 16 | func TestAccElasticsearchSnapshotRepository(t *testing.T) { 17 | resource.Test(t, resource.TestCase{ 18 | PreCheck: func() { testAccPreCheck(t) }, 19 | Providers: testAccProviders, 20 | CheckDestroy: testCheckElasticsearchSnapshotRepositoryDestroy, 21 | Steps: []resource.TestStep{ 22 | { 23 | Config: testAccElasticsearchSnapshotRepository, 24 | Check: resource.ComposeTestCheckFunc( 25 | testCheckElasticsearchSnapshotRepositoryExists("elasticsearch_snapshot_repository.test"), 26 | ), 27 | }, 28 | }, 29 | }) 30 | } 31 | 32 | func TestAccElasticsearchSnapshotRepository_importBasic(t *testing.T) { 33 | resource.Test(t, resource.TestCase{ 34 | PreCheck: func() { testAccPreCheck(t) }, 35 | Providers: testAccProviders, 36 | CheckDestroy: testCheckElasticsearchSnapshotRepositoryDestroy, 37 | Steps: []resource.TestStep{ 38 | { 39 | Config: testAccElasticsearchSnapshotRepository, 40 | }, 41 | { 42 | ResourceName: "elasticsearch_snapshot_repository.test", 43 | ImportState: true, 44 | ImportStateVerify: true, 45 | }, 46 | }, 47 | }) 48 | } 49 | 50 | func testCheckElasticsearchSnapshotRepositoryExists(name string) resource.TestCheckFunc { 51 | return func(s *terraform.State) error { 52 | rs, ok := s.RootModule().Resources[name] 53 | if !ok { 54 | return fmt.Errorf("Not found: %s", name) 55 | } 56 | if rs.Primary.ID == "" { 57 | return fmt.Errorf("No snapshot repository ID is set") 58 | } 59 | 60 | meta := testAccProvider.Meta() 61 | 62 | var err error 63 | esClient, err := getClient(meta.(*ProviderConf)) 64 | if err != nil { 65 | return err 66 | } 67 | switch client := esClient.(type) { 68 | case *elastic7.Client: 69 | _, err = client.SnapshotGetRepository(rs.Primary.ID).Do(context.TODO()) 70 | case *elastic6.Client: 71 | _, err = client.SnapshotGetRepository(rs.Primary.ID).Do(context.TODO()) 72 | default: 73 | return errors.New("Elasticsearch version not supported") 74 | } 75 | 76 | if err != nil { 77 | return err 78 | } 79 | 80 | return nil 81 | } 82 | } 83 | 84 | func testCheckElasticsearchSnapshotRepositoryDestroy(s *terraform.State) error { 85 | for _, rs := range s.RootModule().Resources { 86 | if rs.Type != "elasticsearch_snapshot_repository" { 87 | continue 88 | } 89 | 90 | meta := testAccProvider.Meta() 91 | 92 | var err error 93 | esClient, err := getClient(meta.(*ProviderConf)) 94 | if err != nil { 95 | return err 96 | } 97 | switch client := esClient.(type) { 98 | case *elastic7.Client: 99 | _, err = client.SnapshotGetRepository(rs.Primary.ID).Do(context.TODO()) 100 | case *elastic6.Client: 101 | _, err = client.SnapshotGetRepository(rs.Primary.ID).Do(context.TODO()) 102 | default: 103 | return errors.New("Elasticsearch version not supported") 104 | } 105 | 106 | if err != nil { 107 | return nil // should be not found error 108 | } 109 | 110 | return fmt.Errorf("Snapshot repository %q still exists", rs.Primary.ID) 111 | } 112 | 113 | return nil 114 | } 115 | 116 | var testAccElasticsearchSnapshotRepository = ` 117 | resource "elasticsearch_snapshot_repository" "test" { 118 | name = "terraform-test" 119 | type = "fs" 120 | 121 | settings = { 122 | location = "/tmp/elasticsearch" 123 | } 124 | } 125 | ` 126 | -------------------------------------------------------------------------------- /es/resource_elasticsearch_xpack_index_lifecycle_policy.go: -------------------------------------------------------------------------------- 1 | package es 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "errors" 7 | 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 9 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" 10 | elastic7 "github.com/olivere/elastic/v7" 11 | elastic6 "gopkg.in/olivere/elastic.v6" 12 | ) 13 | 14 | var xPackIndexLifecyclePolicySchema = map[string]*schema.Schema{ 15 | "name": { 16 | Type: schema.TypeString, 17 | ForceNew: true, 18 | Required: true, 19 | }, 20 | "body": { 21 | Type: schema.TypeString, 22 | Required: true, 23 | DiffSuppressFunc: diffSuppressIndexLifecyclePolicy, 24 | ValidateFunc: validation.StringIsJSON, 25 | }, 26 | } 27 | 28 | func resourceElasticsearchXpackIndexLifecyclePolicy() *schema.Resource { 29 | return &schema.Resource{ 30 | Create: resourceElasticsearchXpackIndexLifecyclePolicyCreate, 31 | Read: resourceElasticsearchXpackIndexLifecyclePolicyRead, 32 | Update: resourceElasticsearchXpackIndexLifecyclePolicyUpdate, 33 | Delete: resourceElasticsearchXpackIndexLifecyclePolicyDelete, 34 | Schema: xPackIndexLifecyclePolicySchema, 35 | Importer: &schema.ResourceImporter{ 36 | StateContext: schema.ImportStatePassthroughContext, 37 | }, 38 | } 39 | } 40 | 41 | func resourceElasticsearchXpackIndexLifecyclePolicyCreate(d *schema.ResourceData, meta interface{}) error { 42 | err := resourceElasticsearchPutIndexLifecyclePolicy(d, meta) 43 | if err != nil { 44 | return err 45 | } 46 | d.SetId(d.Get("name").(string)) 47 | return nil 48 | } 49 | 50 | func resourceElasticsearchXpackIndexLifecyclePolicyRead(d *schema.ResourceData, meta interface{}) error { 51 | id := d.Id() 52 | 53 | var result string 54 | var err error 55 | esClient, err := getClient(meta.(*ProviderConf)) 56 | if err != nil { 57 | return err 58 | } 59 | switch client := esClient.(type) { 60 | case *elastic7.Client: 61 | result, err = elastic7IndexGetLifecyclePolicy(client, id) 62 | case *elastic6.Client: 63 | result, err = elastic6IndexGetLifecyclePolicy(client, id) 64 | default: 65 | err = errors.New("Index Lifecycle Management is only supported by the elastic library >= v6!") 66 | } 67 | if err != nil { 68 | return err 69 | } 70 | 71 | ds := &resourceDataSetter{d: d} 72 | ds.set("name", d.Id()) 73 | ds.set("body", result) 74 | return ds.err 75 | } 76 | 77 | func elastic7IndexGetLifecyclePolicy(client *elastic7.Client, id string) (string, error) { 78 | res, err := client.XPackIlmGetLifecycle().Policy(id).Do(context.TODO()) 79 | if err != nil { 80 | return "", err 81 | } 82 | 83 | t := res[id] 84 | tj, err := json.Marshal(t) 85 | if err != nil { 86 | return "", err 87 | } 88 | return string(tj), nil 89 | } 90 | 91 | func elastic6IndexGetLifecyclePolicy(client *elastic6.Client, id string) (string, error) { 92 | res, err := client.XPackIlmGetLifecycle().Policy(id).Do(context.TODO()) 93 | if err != nil { 94 | return "", err 95 | } 96 | 97 | t := res[id] 98 | tj, err := json.Marshal(t) 99 | if err != nil { 100 | return "", err 101 | } 102 | return string(tj), nil 103 | } 104 | 105 | func resourceElasticsearchXpackIndexLifecyclePolicyUpdate(d *schema.ResourceData, meta interface{}) error { 106 | return resourceElasticsearchPutIndexLifecyclePolicy(d, meta) 107 | } 108 | 109 | func resourceElasticsearchXpackIndexLifecyclePolicyDelete(d *schema.ResourceData, meta interface{}) error { 110 | id := d.Id() 111 | 112 | var err error 113 | esClient, err := getClient(meta.(*ProviderConf)) 114 | if err != nil { 115 | return err 116 | } 117 | switch client := esClient.(type) { 118 | case *elastic7.Client: 119 | err = elastic7IndexDeleteLifecyclePolicy(client, id) 120 | case *elastic6.Client: 121 | err = elastic6IndexDeleteLifecyclePolicy(client, id) 122 | default: 123 | err = errors.New("Index Lifecycle Management is only supported by the elastic library >= v6!") 124 | } 125 | 126 | if err != nil { 127 | return err 128 | } 129 | d.SetId("") 130 | return nil 131 | } 132 | 133 | func elastic7IndexDeleteLifecyclePolicy(client *elastic7.Client, id string) error { 134 | _, err := client.XPackIlmDeleteLifecycle().Policy(id).Do(context.TODO()) 135 | return err 136 | } 137 | 138 | func elastic6IndexDeleteLifecyclePolicy(client *elastic6.Client, id string) error { 139 | _, err := client.XPackIlmDeleteLifecycle().Policy(id).Do(context.TODO()) 140 | return err 141 | } 142 | 143 | func resourceElasticsearchPutIndexLifecyclePolicy(d *schema.ResourceData, meta interface{}) error { 144 | name := d.Get("name").(string) 145 | body := d.Get("body").(string) 146 | 147 | var err error 148 | esClient, err := getClient(meta.(*ProviderConf)) 149 | if err != nil { 150 | return err 151 | } 152 | switch client := esClient.(type) { 153 | case *elastic7.Client: 154 | err = elastic7IndexPutLifecyclePolicy(client, name, body) 155 | case *elastic6.Client: 156 | err = elastic6IndexPutLifecyclePolicy(client, name, body) 157 | default: 158 | err = errors.New("resourceElasticsearchPutIndexLifecyclePolicy Index Lifecycle Management is only supported by the elastic library >= v6!") 159 | } 160 | 161 | return err 162 | } 163 | 164 | func elastic7IndexPutLifecyclePolicy(client *elastic7.Client, name string, body string) error { 165 | _, err := client.XPackIlmPutLifecycle().Policy(name).BodyString(body).Do(context.TODO()) 166 | return err 167 | } 168 | 169 | func elastic6IndexPutLifecyclePolicy(client *elastic6.Client, name string, body string) error { 170 | _, err := client.XPackIlmPutLifecycle().Policy(name).BodyString(body).Do(context.TODO()) 171 | return err 172 | } 173 | -------------------------------------------------------------------------------- /es/resource_elasticsearch_xpack_index_lifecycle_policy_test.go: -------------------------------------------------------------------------------- 1 | package es 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "testing" 8 | 9 | elastic7 "github.com/olivere/elastic/v7" 10 | elastic6 "gopkg.in/olivere/elastic.v6" 11 | 12 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 13 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" 14 | ) 15 | 16 | func TestAccElasticsearchXpackIndexLifecyclePolicy(t *testing.T) { 17 | provider := Provider() 18 | diags := provider.Configure(context.Background(), &terraform.ResourceConfig{}) 19 | if diags.HasError() { 20 | t.Skipf("err: %#v", diags) 21 | } 22 | 23 | meta := provider.Meta() 24 | esClient, err := getClient(meta.(*ProviderConf)) 25 | if err != nil { 26 | t.Skipf("err: %s", err) 27 | } 28 | 29 | var config string 30 | var allowed bool 31 | switch esClient.(type) { 32 | case *elastic6.Client: 33 | allowed = true 34 | config = testAccElasticsearch6XpackIndexLifecyclePolicy 35 | default: 36 | allowed = true 37 | config = testAccElasticsearch7XpackIndexLifecyclePolicy 38 | } 39 | 40 | resource.Test(t, resource.TestCase{ 41 | PreCheck: func() { 42 | testAccPreCheck(t) 43 | if !allowed { 44 | t.Skip("Index lifecycles only supported on ES >= 6") 45 | } 46 | }, 47 | Providers: testAccXPackProviders, 48 | CheckDestroy: testCheckElasticsearchXpackIndexLifecyclePolicyDestroy, 49 | Steps: []resource.TestStep{ 50 | { 51 | Config: config, 52 | Check: resource.ComposeTestCheckFunc( 53 | testCheckElasticsearchXpackIndexLifecyclePolicyExists("elasticsearch_xpack_index_lifecycle_policy.test"), 54 | ), 55 | }, 56 | }, 57 | }) 58 | } 59 | 60 | func TestAccElasticsearchXpackIndexLifecyclePolicy_importBasic(t *testing.T) { 61 | provider := Provider() 62 | diags := provider.Configure(context.Background(), &terraform.ResourceConfig{}) 63 | if diags.HasError() { 64 | t.Skipf("err: %#v", diags) 65 | } 66 | 67 | meta := provider.Meta() 68 | esClient, err := getClient(meta.(*ProviderConf)) 69 | if err != nil { 70 | t.Skipf("err: %s", err) 71 | } 72 | 73 | var config string 74 | var allowed bool 75 | switch esClient.(type) { 76 | case *elastic6.Client: 77 | allowed = true 78 | config = testAccElasticsearch6XpackIndexLifecyclePolicy 79 | default: 80 | allowed = true 81 | config = testAccElasticsearch7XpackIndexLifecyclePolicy 82 | } 83 | 84 | resource.Test(t, resource.TestCase{ 85 | PreCheck: func() { 86 | testAccPreCheck(t) 87 | if !allowed { 88 | t.Skip("Index lifecycles only supported on ES >= 6") 89 | } 90 | }, 91 | Providers: testAccXPackProviders, 92 | CheckDestroy: testCheckElasticsearchXpackIndexLifecyclePolicyDestroy, 93 | Steps: []resource.TestStep{ 94 | { 95 | Config: config, 96 | }, 97 | { 98 | ResourceName: "elasticsearch_xpack_index_lifecycle_policy.test", 99 | ImportState: true, 100 | ImportStateVerify: true, 101 | }, 102 | }, 103 | }) 104 | } 105 | 106 | func testCheckElasticsearchXpackIndexLifecyclePolicyExists(name string) resource.TestCheckFunc { 107 | return func(s *terraform.State) error { 108 | rs, ok := s.RootModule().Resources[name] 109 | if !ok { 110 | return fmt.Errorf("Not found: %s", name) 111 | } 112 | if rs.Primary.ID == "" { 113 | return fmt.Errorf("No index lifecycle policy ID is set") 114 | } 115 | 116 | meta := testAccXPackProvider.Meta() 117 | 118 | var err error 119 | esClient, err := getClient(meta.(*ProviderConf)) 120 | if err != nil { 121 | return err 122 | } 123 | switch client := esClient.(type) { 124 | case *elastic7.Client: 125 | _, err = client.XPackIlmGetLifecycle().Policy(rs.Primary.ID).Do(context.TODO()) 126 | case *elastic6.Client: 127 | _, err = client.XPackIlmGetLifecycle().Policy(rs.Primary.ID).Do(context.TODO()) 128 | default: 129 | err = errors.New("Index Lifecycle Management is only supported by the elastic library >= v6!") 130 | } 131 | 132 | if err != nil { 133 | return err 134 | } 135 | 136 | return nil 137 | } 138 | } 139 | 140 | func testCheckElasticsearchXpackIndexLifecyclePolicyDestroy(s *terraform.State) error { 141 | for _, rs := range s.RootModule().Resources { 142 | if rs.Type != "elasticsearch_xpack_index_lifecycle_policy" { 143 | continue 144 | } 145 | 146 | meta := testAccXPackProvider.Meta() 147 | 148 | var err error 149 | esClient, err := getClient(meta.(*ProviderConf)) 150 | if err != nil { 151 | return err 152 | } 153 | switch client := esClient.(type) { 154 | case *elastic7.Client: 155 | _, err = client.XPackIlmGetLifecycle().Policy(rs.Primary.ID).Do(context.TODO()) 156 | case *elastic6.Client: 157 | _, err = client.XPackIlmGetLifecycle().Policy(rs.Primary.ID).Do(context.TODO()) 158 | default: 159 | err = errors.New("Index Lifecycle Management is only supported by the elastic library >= v6!") 160 | } 161 | 162 | if err != nil { 163 | return nil // should be not found error 164 | } 165 | 166 | return fmt.Errorf("Index lifecycle policy %q still exists", rs.Primary.ID) 167 | } 168 | 169 | return nil 170 | } 171 | 172 | var testAccElasticsearch6XpackIndexLifecyclePolicy = ` 173 | resource "elasticsearch_xpack_index_lifecycle_policy" "test" { 174 | name = "terraform-test" 175 | body = <= v6!") 69 | } 70 | 71 | if err != nil { 72 | return err 73 | } 74 | 75 | return nil 76 | } 77 | } 78 | 79 | func testCheckElasticsearchLicenseDestroy(s *terraform.State) error { 80 | for _, rs := range s.RootModule().Resources { 81 | if rs.Type != "elasticsearch_xpack_license" { 82 | continue 83 | } 84 | 85 | meta := testAccXPackProvider.Meta() 86 | 87 | esClient, err := getClient(meta.(*ProviderConf)) 88 | if err != nil { 89 | return err 90 | } 91 | switch client := esClient.(type) { 92 | case *elastic7.Client: 93 | resp, err := client.XPackInfo().Do(context.TODO()) 94 | log.Printf("[INFO] testCheckElasticsearchLicenseDestroy %+v", resp) 95 | 96 | if err != nil { 97 | return err 98 | } 99 | 100 | // See https://github.com/elastic/elasticsearch/pull/52407, deleting a 101 | // basic license is a no-op 102 | if resp.License.Type != "basic" && resp.License.UID != "" { 103 | return fmt.Errorf("License still exists") 104 | } else if resp.License.Type == "basic" && resp.License.UID == "" { 105 | return nil 106 | } 107 | case *elastic6.Client: 108 | resp, err := client.XPackInfo().Do(context.TODO()) 109 | log.Printf("[INFO] testCheckElasticsearchLicenseDestroy %+v", resp) 110 | licenseUID := resp.License.UID 111 | 112 | if err != nil { 113 | return err 114 | } 115 | 116 | if licenseUID != "" { 117 | return fmt.Errorf("License still exists") 118 | } 119 | default: 120 | return errors.New("License is only supported by elasticsearch >= v6!") 121 | } 122 | 123 | return nil 124 | } 125 | 126 | return nil 127 | } 128 | 129 | var testElasticsearchLicense = ` 130 | resource "elasticsearch_xpack_license" "test" { 131 | use_basic_license = "true" 132 | } 133 | ` 134 | -------------------------------------------------------------------------------- /es/resource_elasticsearch_xpack_snapshot_lifecycle_policy.go: -------------------------------------------------------------------------------- 1 | package es 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "errors" 7 | "net/http" 8 | 9 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 10 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" 11 | elastic7 "github.com/olivere/elastic/v7" 12 | ) 13 | 14 | func resourceElasticsearchXpackSnapshotLifecyclePolicy() *schema.Resource { 15 | return &schema.Resource{ 16 | Description: "Provides an Elasticsearch XPack snapshot lifecycle management policy. These automatically take snapshots and control how long they are retained. See the upstream [docs](https://www.elastic.co/guide/en/elasticsearch/reference/current/snapshot-lifecycle-management-api.html) for more details.", 17 | Create: resourceElasticsearchXpackSnapshotLifecyclePolicyCreate, 18 | Read: resourceElasticsearchXpackSnapshotLifecyclePolicyRead, 19 | Update: resourceElasticsearchXpackSnapshotLifecyclePolicyUpdate, 20 | Delete: resourceElasticsearchXpackSnapshotLifecyclePolicyDelete, 21 | Schema: map[string]*schema.Schema{ 22 | "name": { 23 | Type: schema.TypeString, 24 | ForceNew: true, 25 | Required: true, 26 | Description: "ID for the snapshot lifecycle policy", 27 | }, 28 | "body": { 29 | Type: schema.TypeString, 30 | Required: true, 31 | DiffSuppressFunc: diffSuppressSnapshotLifecyclePolicy, 32 | ValidateFunc: validation.StringIsJSON, 33 | Description: "See the policy definition defined in the [docs](https://www.elastic.co/guide/en/elasticsearch/reference/current/slm-api-put-policy.html#slm-api-put-request-body)", 34 | }, 35 | }, 36 | Importer: &schema.ResourceImporter{ 37 | StateContext: schema.ImportStatePassthroughContext, 38 | }, 39 | } 40 | } 41 | 42 | func resourceElasticsearchXpackSnapshotLifecyclePolicyCreate(d *schema.ResourceData, meta interface{}) error { 43 | err := resourceElasticsearchPutSnapshotLifecyclePolicy(d, meta) 44 | if err != nil { 45 | return err 46 | } 47 | d.SetId(d.Get("name").(string)) 48 | return nil 49 | } 50 | 51 | func resourceElasticsearchXpackSnapshotLifecyclePolicyRead(d *schema.ResourceData, meta interface{}) error { 52 | id := d.Id() 53 | 54 | var result string 55 | var err error 56 | esClient, err := getClient(meta.(*ProviderConf)) 57 | if err != nil { 58 | return err 59 | } 60 | switch client := esClient.(type) { 61 | case *elastic7.Client: 62 | result, err = elastic7SnapshotGetLifecyclePolicy(client, id) 63 | default: 64 | err = errors.New("Snapshot Lifecycle Management is only supported by the elastic library >= v7!") 65 | } 66 | if err != nil { 67 | return err 68 | } 69 | 70 | ds := &resourceDataSetter{d: d} 71 | ds.set("name", d.Id()) 72 | ds.set("body", result) 73 | return ds.err 74 | } 75 | 76 | func elastic7SnapshotGetLifecyclePolicy(client *elastic7.Client, id string) (string, error) { 77 | res, err := client.PerformRequest(context.TODO(), elastic7.PerformRequestOptions{ 78 | Method: http.MethodGet, 79 | Path: "/_slm/policy/" + id, 80 | }) 81 | if err != nil { 82 | return "", err 83 | } 84 | 85 | // GET /_slm/policy/{id} returns a more unique object than other similar 86 | // API endpoints: 87 | // this returns a map[policyname]{policy} 88 | // EVEN IF we specify the id 89 | // https://www.elastic.co/guide/en/elasticsearch/reference/7.x/slm-api-get-policy.html 90 | 91 | // so we need to do our part to reduce this to just the policy object 92 | // which is the equivalent of our "body" elsewhere 93 | var resp map[string]interface{} 94 | if err := json.Unmarshal(res.Body, &resp); err != nil { 95 | return "", err 96 | } 97 | 98 | policy, ok := resp[id] 99 | if !ok { 100 | return "", errors.New("Snapshot Lifecycle Management unsuccessfully parsed") 101 | } 102 | 103 | typedPolicy, ok := policy.(map[string]interface{}) 104 | if !ok { 105 | return "", errors.New("Snapshot Lifecycle Management unsuccessfully parsed") 106 | } 107 | 108 | tj, err := json.Marshal(typedPolicy["policy"]) 109 | if err != nil { 110 | return "", err 111 | } 112 | 113 | return string(tj), nil 114 | } 115 | 116 | func resourceElasticsearchXpackSnapshotLifecyclePolicyUpdate(d *schema.ResourceData, meta interface{}) error { 117 | return resourceElasticsearchPutSnapshotLifecyclePolicy(d, meta) 118 | } 119 | 120 | func resourceElasticsearchXpackSnapshotLifecyclePolicyDelete(d *schema.ResourceData, meta interface{}) error { 121 | id := d.Id() 122 | 123 | var err error 124 | esClient, err := getClient(meta.(*ProviderConf)) 125 | if err != nil { 126 | return err 127 | } 128 | switch client := esClient.(type) { 129 | case *elastic7.Client: 130 | err = elastic7SnapshotDeleteLifecyclePolicy(client, id) 131 | default: 132 | err = errors.New("Snapshot Lifecycle Management is only supported by the elastic library >= v7!") 133 | } 134 | 135 | if err != nil { 136 | return err 137 | } 138 | d.SetId("") 139 | return nil 140 | } 141 | 142 | func elastic7SnapshotDeleteLifecyclePolicy(client *elastic7.Client, id string) error { 143 | _, err := client.PerformRequest(context.TODO(), elastic7.PerformRequestOptions{ 144 | Method: http.MethodDelete, 145 | Path: "/_slm/policy/" + id, 146 | }) 147 | return err 148 | } 149 | 150 | func resourceElasticsearchPutSnapshotLifecyclePolicy(d *schema.ResourceData, meta interface{}) error { 151 | name := d.Get("name").(string) 152 | body := d.Get("body").(string) 153 | 154 | var err error 155 | esClient, err := getClient(meta.(*ProviderConf)) 156 | if err != nil { 157 | return err 158 | } 159 | switch client := esClient.(type) { 160 | case *elastic7.Client: 161 | err = elastic7SnapshotPutLifecyclePolicy(client, name, body) 162 | default: 163 | err = errors.New("resourceElasticsearchPutSnapshotLifecyclePolicy Snapshot Lifecycle Management is only supported by the elastic library >= v7!") 164 | } 165 | 166 | return err 167 | } 168 | 169 | func elastic7SnapshotPutLifecyclePolicy(client *elastic7.Client, name string, body string) error { 170 | _, err := client.PerformRequest(context.TODO(), elastic7.PerformRequestOptions{ 171 | Method: http.MethodPut, 172 | Path: "/_slm/policy/" + name, 173 | Body: body, 174 | }) 175 | return err 176 | } 177 | -------------------------------------------------------------------------------- /es/resource_elasticsearch_xpack_snapshot_lifecycle_policy_test.go: -------------------------------------------------------------------------------- 1 | package es 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "net/http" 8 | "testing" 9 | 10 | elastic7 "github.com/olivere/elastic/v7" 11 | elastic6 "gopkg.in/olivere/elastic.v6" 12 | 13 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" 14 | "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" 15 | ) 16 | 17 | func TestAccElasticsearchXpackSnapshotLifecyclePolicy(t *testing.T) { 18 | provider := Provider() 19 | diags := provider.Configure(context.Background(), &terraform.ResourceConfig{}) 20 | if diags.HasError() { 21 | t.Skipf("err: %#v", diags) 22 | } 23 | meta := provider.Meta() 24 | esClient, err := getClient(meta.(*ProviderConf)) 25 | if err != nil { 26 | t.Skipf("err: %s", err) 27 | } 28 | var allowed bool 29 | switch esClient.(type) { 30 | case *elastic6.Client: 31 | allowed = false 32 | default: 33 | allowed = true 34 | } 35 | 36 | resource.Test(t, resource.TestCase{ 37 | PreCheck: func() { 38 | testAccPreCheck(t) 39 | if !allowed { 40 | t.Skip("Snapshot lifecycles only supported on ES >= 7") 41 | } 42 | }, 43 | Providers: testAccXPackProviders, 44 | CheckDestroy: testCheckElasticsearchXpackSnapshotLifecyclePolicyDestroy, 45 | Steps: []resource.TestStep{ 46 | { 47 | Config: testAccElasticsearchSnapshotRepository, 48 | }, 49 | { 50 | Config: testAccElasticsearchXpackSnapshotLifecyclePolicy, 51 | Check: resource.ComposeTestCheckFunc( 52 | testCheckElasticsearchXpackSnapshotLifecyclePolicyExists("elasticsearch_xpack_snapshot_lifecycle_policy.terraform-test"), 53 | ), 54 | }, 55 | }, 56 | }) 57 | } 58 | 59 | func TestAccElasticsearchXpackSnapshotLifecyclePolicy_importBasic(t *testing.T) { 60 | provider := Provider() 61 | diags := provider.Configure(context.Background(), &terraform.ResourceConfig{}) 62 | if diags.HasError() { 63 | t.Skipf("err: %#v", diags) 64 | } 65 | meta := provider.Meta() 66 | var allowed bool 67 | esClient, err := getClient(meta.(*ProviderConf)) 68 | if err != nil { 69 | t.Skipf("err: %s", err) 70 | } 71 | switch esClient.(type) { 72 | case *elastic6.Client: 73 | allowed = false 74 | default: 75 | allowed = true 76 | } 77 | 78 | resource.Test(t, resource.TestCase{ 79 | PreCheck: func() { 80 | testAccPreCheck(t) 81 | if !allowed { 82 | t.Skip("Snapshot lifecycles only supported on ES >= 7") 83 | } 84 | }, 85 | Providers: testAccXPackProviders, 86 | CheckDestroy: testCheckElasticsearchXpackSnapshotLifecyclePolicyDestroy, 87 | Steps: []resource.TestStep{ 88 | { 89 | Config: testAccElasticsearchSnapshotRepository, 90 | }, 91 | { 92 | Config: testAccElasticsearchXpackSnapshotLifecyclePolicy, 93 | }, 94 | { 95 | ResourceName: "elasticsearch_xpack_snapshot_lifecycle_policy.terraform-test", 96 | ImportState: true, 97 | ImportStateVerify: true, 98 | }, 99 | }, 100 | }) 101 | } 102 | 103 | func testCheckElasticsearchXpackSnapshotLifecyclePolicyExists(name string) resource.TestCheckFunc { 104 | return func(s *terraform.State) error { 105 | rs, ok := s.RootModule().Resources[name] 106 | if !ok { 107 | return fmt.Errorf("Not found: %s", name) 108 | } 109 | if rs.Primary.ID == "" { 110 | return fmt.Errorf("No snapshot lifecycle policy ID is set") 111 | } 112 | 113 | meta := testAccXPackProvider.Meta() 114 | 115 | var err error 116 | esClient, err := getClient(meta.(*ProviderConf)) 117 | if err != nil { 118 | return err 119 | } 120 | switch client := esClient.(type) { 121 | case *elastic7.Client: 122 | _, err = client.PerformRequest(context.TODO(), elastic7.PerformRequestOptions{Method: http.MethodGet, Path: "/_slm/policy/" + rs.Primary.ID}) 123 | default: 124 | err = errors.New("Snapshot Lifecycle Management is only supported by the elastic library >= v7!") 125 | } 126 | 127 | if err != nil { 128 | return err 129 | } 130 | 131 | return nil 132 | } 133 | } 134 | 135 | func testCheckElasticsearchXpackSnapshotLifecyclePolicyDestroy(s *terraform.State) error { 136 | for _, rs := range s.RootModule().Resources { 137 | if rs.Type != "elasticsearch_xpack_snapshot_lifecycle_policy" { 138 | continue 139 | } 140 | 141 | meta := testAccXPackProvider.Meta() 142 | 143 | var err error 144 | esClient, err := getClient(meta.(*ProviderConf)) 145 | if err != nil { 146 | return err 147 | } 148 | switch client := esClient.(type) { 149 | case *elastic7.Client: 150 | _, err = client.PerformRequest(context.TODO(), elastic7.PerformRequestOptions{Method: http.MethodDelete, Path: "/_slm/policy/" + rs.Primary.ID}) 151 | default: 152 | err = errors.New("Snapshot Lifecycle Management is only supported by the elastic library >= v7!") 153 | } 154 | 155 | if err != nil { 156 | return nil // should be not found error 157 | } 158 | 159 | return fmt.Errorf("Snapshot lifecycle policy %q still exists", rs.Primary.ID) 160 | } 161 | 162 | return nil 163 | } 164 | 165 | var testAccElasticsearchXpackSnapshotLifecyclePolicy = ` 166 | resource "elasticsearch_snapshot_repository" "test" { 167 | name = "terraform-test" 168 | type = "fs" 169 | settings = { 170 | location = "/tmp/elasticsearch" 171 | } 172 | } 173 | 174 | resource "elasticsearch_xpack_snapshot_lifecycle_policy" "terraform-test" { 175 | name = "terraformtest" 176 | body = <", 180 | "repository": "${elasticsearch_snapshot_repository.test.name}", 181 | "config": { 182 | "indices": ["data-*", "important"], 183 | "ignore_unavailable": false, 184 | "include_global_state": false 185 | }, 186 | "retention": { 187 | "expire_after": "30d", 188 | "min_count": 5, 189 | "max_count": 50 190 | } 191 | } 192 | EOF 193 | } 194 | ` 195 | -------------------------------------------------------------------------------- /es/resource_elasticsearch_xpack_watch_test.go: -------------------------------------------------------------------------------- 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 TestAccElasticsearchWatch(t *testing.T) { 16 | resource.ParallelTest(t, resource.TestCase{ 17 | PreCheck: func() { 18 | testAccPreCheck(t) 19 | }, 20 | Providers: testAccXPackProviders, 21 | CheckDestroy: testCheckElasticsearchWatchDestroy, 22 | Steps: []resource.TestStep{ 23 | { 24 | Config: testAccElasticsearchWatch, 25 | Check: resource.ComposeTestCheckFunc( 26 | testCheckElasticsearchWatchExists("elasticsearch_xpack_watch.test_watch"), 27 | testCheckElasticsearchWatchDeactivated("elasticsearch_xpack_watch.test_watch"), 28 | ), 29 | }, 30 | }, 31 | }) 32 | } 33 | 34 | func testCheckElasticsearchWatchDeactivated(name string) resource.TestCheckFunc { 35 | return func(s *terraform.State) error { 36 | rs, ok := s.RootModule().Resources[name] 37 | if !ok { 38 | return fmt.Errorf("Not found: %s", name) 39 | } 40 | if rs.Primary.ID == "" { 41 | return fmt.Errorf("No watch ID is set") 42 | } 43 | 44 | meta := testAccXPackProvider.Meta() 45 | 46 | var err error 47 | esClient, err := getClient(meta.(*ProviderConf)) 48 | if err != nil { 49 | return err 50 | } 51 | switch client := esClient.(type) { 52 | case *elastic7.Client: 53 | watcher, err := client.XPackWatchGet("my_watch").Do(context.TODO()) 54 | if err != nil { 55 | return err 56 | } 57 | if watcher.Status.State.Active { 58 | return fmt.Errorf("Watcher should be in deactivate state") 59 | } 60 | case *elastic6.Client: 61 | watcher, err := client.XPackWatchGet("my_watch").Do(context.TODO()) 62 | if err != nil { 63 | return err 64 | } 65 | if watcher.Status.State.Active { 66 | return fmt.Errorf("Watcher should be in deactivate state") 67 | } 68 | default: 69 | } 70 | 71 | if err != nil { 72 | return err 73 | } 74 | 75 | return nil 76 | } 77 | } 78 | 79 | func testCheckElasticsearchWatchExists(name string) resource.TestCheckFunc { 80 | return func(s *terraform.State) error { 81 | rs, ok := s.RootModule().Resources[name] 82 | if !ok { 83 | return fmt.Errorf("Not found: %s", name) 84 | } 85 | if rs.Primary.ID == "" { 86 | return fmt.Errorf("No watch ID is set") 87 | } 88 | 89 | meta := testAccXPackProvider.Meta() 90 | 91 | var err error 92 | esClient, err := getClient(meta.(*ProviderConf)) 93 | if err != nil { 94 | return err 95 | } 96 | switch client := esClient.(type) { 97 | case *elastic7.Client: 98 | _, err = client.XPackWatchGet("my_watch").Do(context.TODO()) 99 | case *elastic6.Client: 100 | _, err = client.XPackWatchGet("my_watch").Do(context.TODO()) 101 | default: 102 | } 103 | 104 | if err != nil { 105 | return err 106 | } 107 | 108 | return nil 109 | } 110 | } 111 | 112 | func testCheckElasticsearchWatchDestroy(s *terraform.State) error { 113 | for _, rs := range s.RootModule().Resources { 114 | if rs.Type != "elasticsearch_xpack_watch" { 115 | continue 116 | } 117 | 118 | meta := testAccXPackProvider.Meta() 119 | 120 | var err error 121 | esClient, err := getClient(meta.(*ProviderConf)) 122 | if err != nil { 123 | return err 124 | } 125 | switch client := esClient.(type) { 126 | case *elastic7.Client: 127 | _, err = client.XPackWatchGet("my_watch").Do(context.TODO()) 128 | case *elastic6.Client: 129 | _, err = client.XPackWatchGet("my_watch").Do(context.TODO()) 130 | default: 131 | } 132 | 133 | if err != nil { 134 | return nil // should be not found error 135 | } 136 | 137 | return fmt.Errorf("Watch %q still exists", rs.Primary.ID) 138 | } 139 | 140 | return nil 141 | } 142 | 143 | var testAccElasticsearchWatch = ` 144 | resource "elasticsearch_xpack_watch" "test_watch" { 145 | watch_id = "my_watch" 146 | active = false 147 | body = <%%{YEAR}[./]%%{MONTHNUM}[./]%%{MONTHDAY} %%{TIME}) \[%%{LOGLEVEL:severity}\] %%{POSINT:pid}#%%{NUMBER:threadid}\:( \*%%{NUMBER:connectionid})? %%{DATA:message}(,|$)( client: %%{IPORHOST:client})?(, server: %%{IPORHOST:server})?(, request: "(?:%%{WORD:verb} %%{NOTSPACE:request}(?: HTTP/%%{NUMBER:httpversion}))")?(, upstream: "%%{DATA:upstream}")?(, host: "%%{IPORHOST:vhost}")?""" 45 | ] 46 | } 47 | }, 48 | { 49 | "date": { 50 | "field": "timestamp", 51 | "formats": [ 52 | "YYYY/MM/dd HH:mm:ss" 53 | ] 54 | } 55 | } 56 | ] 57 | } 58 | EOF 59 | } 60 | -------------------------------------------------------------------------------- /examples/resources/elasticsearch_audit_config/import.sh: -------------------------------------------------------------------------------- 1 | # Import by name 2 | terraform import elasticsearch_opensearch_audit_config.test_config my-config -------------------------------------------------------------------------------- /examples/resources/elasticsearch_audit_config/resource.tf: -------------------------------------------------------------------------------- 1 | resource "elasticsearch_opensearch_audit_config" "test" { 2 | enabled = true 3 | 4 | audit { 5 | enable_rest = true 6 | disabled_rest_categories = ["GRANTED_PRIVILEGES", "AUTHENTICATED"] 7 | 8 | enable_transport = true 9 | disabled_transport_categories = ["GRANTED_PRIVILEGES", "AUTHENTICATED"] 10 | 11 | resolve_bulk_requests = true 12 | log_request_body = true 13 | resolve_indices = true 14 | 15 | # Note: if set false, AWS OpenSearch will return HTTP 409 (Conflict) 16 | exclude_sensitive_headers = true 17 | 18 | ignore_users = ["kibanaserver"] 19 | ignore_requests = ["SearchRequest", "indices:data/read/*", "/_cluster/health"] 20 | } 21 | 22 | compliance { 23 | enabled = true 24 | 25 | # Note: if both internal/external are set true, AWS OpenSearch will return HTTP 409 (Conflict) 26 | internal_config = true 27 | external_config = false 28 | 29 | read_metadata_only = true 30 | read_ignore_users = ["read-ignore-1"] 31 | 32 | read_watched_field { 33 | index = "read-index-1" 34 | fields = ["field-1", "field-2"] 35 | } 36 | 37 | read_watched_field { 38 | index = "read-index-2" 39 | fields = ["field-3"] 40 | } 41 | 42 | write_metadata_only = true 43 | write_log_diffs = false 44 | write_watched_indices = ["write-index-1", "write-index-2", "log-*", "*"] 45 | write_ignore_users = ["write-ignore-1"] 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /examples/resources/elasticsearch_cluster_settings/resource.tf: -------------------------------------------------------------------------------- 1 | resource "elasticsearch_cluster_settings" "global" { 2 | cluster_max_shards_per_node = 10 3 | action_auto_create_index = "my-index-000001,index10,-index1*,+ind*" 4 | } 5 | -------------------------------------------------------------------------------- /examples/resources/elasticsearch_component_template/import.sh: -------------------------------------------------------------------------------- 1 | # Import by name 2 | terraform import elasticsearch_component_template.test terraform-test 3 | -------------------------------------------------------------------------------- /examples/resources/elasticsearch_component_template/resource.tf: -------------------------------------------------------------------------------- 1 | resource "elasticsearch_component_template" "test" { 2 | name = "terraform-test" 3 | body = <", 7 | "repository": "terraform-test", 8 | "config": { 9 | "indices": ["data-*", "important"], 10 | "ignore_unavailable": false, 11 | "include_global_state": false 12 | }, 13 | "retention": { 14 | "expire_after": "30d", 15 | "min_count": 5, 16 | "max_count": 50 17 | } 18 | } 19 | EOF 20 | } 21 | -------------------------------------------------------------------------------- /examples/resources/elasticsearch_xpack_user/import.sh: -------------------------------------------------------------------------------- 1 | # Import by username 2 | terraform import elasticsearch_xpack_user.test johndoe 3 | -------------------------------------------------------------------------------- /examples/resources/elasticsearch_xpack_user/resource.tf: -------------------------------------------------------------------------------- 1 | resource "elasticsearch_xpack_user" "test" { 2 | username = "johndoe" 3 | fullname = "John DoDo" 4 | email = "john@do.com" 5 | password = "secret" 6 | roles = ["admin"] 7 | metadata = <<-EOF 8 | { 9 | "foo": "bar" 10 | } 11 | EOF 12 | } 13 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/phillbaker/terraform-provider-elasticsearch 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/aws/aws-sdk-go v1.43.21 7 | github.com/deoxxa/aws_signing_client v0.0.0-20161109131055-c20ee106809e 8 | github.com/hashicorp/go-hclog v1.2.0 9 | github.com/hashicorp/go-version v1.4.0 10 | github.com/hashicorp/terraform-plugin-docs v0.4.0 11 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.10.0 12 | github.com/katbyte/terrafmt v0.4.0 13 | github.com/mitchellh/go-homedir v1.1.0 14 | github.com/olivere/elastic v6.2.26+incompatible 15 | github.com/olivere/elastic/v7 v7.0.32 16 | gopkg.in/olivere/elastic.v6 v6.2.37 17 | ) 18 | 19 | require ( 20 | cloud.google.com/go v0.61.0 // indirect 21 | cloud.google.com/go/storage v1.10.0 // indirect 22 | github.com/Masterminds/goutils v1.1.0 // indirect 23 | github.com/Masterminds/semver v1.5.0 // indirect 24 | github.com/Masterminds/sprig v2.22.0+incompatible // indirect 25 | github.com/agext/levenshtein v1.2.3 // indirect 26 | github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 // indirect 27 | github.com/apparentlymart/go-cidr v1.0.1 // indirect 28 | github.com/apparentlymart/go-textseg/v12 v12.0.0 // indirect 29 | github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect 30 | github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 // indirect 31 | github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect 32 | github.com/bgentry/speakeasy v0.1.0 // indirect 33 | github.com/davecgh/go-spew v1.1.1 // indirect 34 | github.com/fatih/color v1.7.0 // indirect 35 | github.com/fsnotify/fsnotify v1.4.9 // indirect 36 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 37 | github.com/golang/protobuf v1.5.2 // indirect 38 | github.com/google/go-cmp v0.5.9 // indirect 39 | github.com/google/uuid v1.1.2 // indirect 40 | github.com/googleapis/gax-go/v2 v2.0.5 // indirect 41 | github.com/gookit/color v1.2.6 // indirect 42 | github.com/hashicorp/errwrap v1.0.0 // indirect 43 | github.com/hashicorp/go-checkpoint v0.5.0 // indirect 44 | github.com/hashicorp/go-cleanhttp v0.5.2 // indirect 45 | github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 // indirect 46 | github.com/hashicorp/go-getter v1.5.3 // indirect 47 | github.com/hashicorp/go-multierror v1.1.1 // indirect 48 | github.com/hashicorp/go-plugin v1.4.1 // indirect 49 | github.com/hashicorp/go-safetemp v1.0.0 // indirect 50 | github.com/hashicorp/go-uuid v1.0.3 // indirect 51 | github.com/hashicorp/hc-install v0.3.2 // indirect 52 | github.com/hashicorp/hcl v1.0.0 // indirect 53 | github.com/hashicorp/hcl/v2 v2.6.0 // indirect 54 | github.com/hashicorp/logutils v1.0.0 // indirect 55 | github.com/hashicorp/terraform-exec v0.15.0 // indirect 56 | github.com/hashicorp/terraform-json v0.13.0 // indirect 57 | github.com/hashicorp/terraform-plugin-go v0.5.0 // indirect 58 | github.com/hashicorp/terraform-plugin-log v0.2.0 // indirect 59 | github.com/hashicorp/terraform-registry-address v0.0.0-20210412075316-9b2996cce896 // indirect 60 | github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 // indirect 61 | github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d // indirect 62 | github.com/huandu/xstrings v1.3.2 // indirect 63 | github.com/imdario/mergo v0.3.12 // indirect 64 | github.com/inconshreveable/mousetrap v1.0.0 // indirect 65 | github.com/jmespath/go-jmespath v0.4.0 // indirect 66 | github.com/josharian/intern v1.0.0 // indirect 67 | github.com/jstemmer/go-junit-report v0.9.1 // indirect 68 | github.com/klauspost/compress v1.11.2 // indirect 69 | github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect 70 | github.com/magiconair/properties v1.8.1 // indirect 71 | github.com/mailru/easyjson v0.7.7 // indirect 72 | github.com/mattn/go-colorable v0.1.8 // indirect 73 | github.com/mattn/go-isatty v0.0.12 // indirect 74 | github.com/mitchellh/cli v1.1.2 // indirect 75 | github.com/mitchellh/copystructure v1.2.0 // indirect 76 | github.com/mitchellh/go-testing-interface v1.14.1 // indirect 77 | github.com/mitchellh/go-wordwrap v1.0.0 // indirect 78 | github.com/mitchellh/mapstructure v1.3.3 // indirect 79 | github.com/mitchellh/reflectwalk v1.0.2 // indirect 80 | github.com/oklog/run v1.0.0 // indirect 81 | github.com/pelletier/go-toml v1.8.0 // indirect 82 | github.com/pkg/errors v0.9.1 // indirect 83 | github.com/posener/complete v1.1.1 // indirect 84 | github.com/russross/blackfriday v1.6.0 // indirect 85 | github.com/sergi/go-diff v1.2.0 // indirect 86 | github.com/sirupsen/logrus v1.6.0 // indirect 87 | github.com/spf13/afero v1.4.1 // indirect 88 | github.com/spf13/cast v1.3.1 // indirect 89 | github.com/spf13/cobra v1.0.0 // indirect 90 | github.com/spf13/jwalterweatherman v1.1.0 // indirect 91 | github.com/spf13/pflag v1.0.5 // indirect 92 | github.com/spf13/viper v1.7.0 // indirect 93 | github.com/subosito/gotenv v1.2.0 // indirect 94 | github.com/ulikunitz/xz v0.5.8 // indirect 95 | github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect 96 | github.com/zclconf/go-cty v1.9.1 // indirect 97 | go.opencensus.io v0.23.0 // indirect 98 | golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd // indirect 99 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect 100 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect 101 | golang.org/x/net v0.7.0 // indirect 102 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect 103 | golang.org/x/sys v0.5.0 // indirect 104 | golang.org/x/text v0.7.0 // indirect 105 | golang.org/x/tools v0.1.12 // indirect 106 | google.golang.org/api v0.29.0 // indirect 107 | google.golang.org/appengine v1.6.6 // indirect 108 | google.golang.org/genproto v0.0.0-20200711021454-869866162049 // indirect 109 | google.golang.org/grpc v1.33.2 // indirect 110 | google.golang.org/protobuf v1.28.0 // indirect 111 | gopkg.in/ini.v1 v1.57.0 // indirect 112 | gopkg.in/yaml.v2 v2.3.0 // indirect 113 | gopkg.in/yaml.v3 v3.0.1 // indirect 114 | ) 115 | -------------------------------------------------------------------------------- /kibana/alerts.go: -------------------------------------------------------------------------------- 1 | package kibana 2 | 3 | type AlertSchedule struct { 4 | Interval string `json:"interval,omitempty"` 5 | } 6 | 7 | type AlertAction struct { 8 | ID string `json:"id"` 9 | Group string `json:"group"` 10 | ActionTypeId string `json:"actionTypeId,omitempty"` 11 | Params map[string]interface{} `json:"params,omitempty"` 12 | } 13 | 14 | type Alert struct { 15 | ID string `json:"id,omitempty"` 16 | Name string `json:"name"` 17 | Tags []string `json:"tags,omitempty"` 18 | AlertTypeID string `json:"alertTypeId,omitempty"` 19 | Schedule AlertSchedule `json:"schedule,omitempty"` 20 | Throttle string `json:"throttle,omitempty"` 21 | NotifyWhen string `json:"notifyWhen,omitempty"` 22 | Enabled bool `json:"enabled,omitempty"` 23 | Consumer string `json:"consumer,omitempty"` 24 | Params map[string]interface{} `json:"params,omitempty"` 25 | Actions []AlertAction `json:"actions,omitempty"` 26 | } 27 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "log" 7 | 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/plugin" 9 | 10 | "github.com/phillbaker/terraform-provider-elasticsearch/es" 11 | ) 12 | 13 | // Generate docs for website 14 | //go:generate go run github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs 15 | 16 | func main() { 17 | var debugMode bool 18 | 19 | flag.BoolVar(&debugMode, "debuggable", false, "set to true to run the provider with support for debuggers like delve") 20 | flag.Parse() 21 | 22 | if debugMode { 23 | err := plugin.Debug(context.Background(), "registry.terraform.io/phillbaker/elasticsearch", 24 | &plugin.ServeOpts{ 25 | ProviderFunc: es.Provider, 26 | }, 27 | ) 28 | if err != nil { 29 | log.Println(err.Error()) 30 | } 31 | } else { 32 | plugin.Serve(&plugin.ServeOpts{ 33 | ProviderFunc: es.Provider, 34 | }) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /script/install-tools: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eo pipefail 3 | 4 | : ${TOOLS_FILE:="tools/tools.go"} 5 | 6 | go install $(go list -f '{{join .Imports " "}}' $TOOLS_FILE) 7 | -------------------------------------------------------------------------------- /script/test-mod-tidy: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | go mod tidy 4 | STATUS=$( git status --porcelain go.mod go.sum ) 5 | if [ ! -z "$STATUS" ]; then 6 | echo "Running go mod tidy modified go.mod and/or go.sum" 7 | git diff 8 | exit 1 9 | fi 10 | exit 0 11 | -------------------------------------------------------------------------------- /script/test-terraform-fmt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eo pipefail 3 | 4 | # test examples are terraform formatted, terraform fmt has non zero exit code 5 | # if there are non canonical files 6 | terraform fmt -recursive -no-color -check -diff examples/ | while IFS= read -r line; do 7 | echo "$line" 8 | 9 | if [[ -f "$line" ]]; then 10 | echo "::error file=$line::File is not in canonical format (terraform fmt)" 11 | fi 12 | done 13 | 14 | # test terraform HCL content in test files is formatted 15 | terrafmt diff -f ./es --check --pattern '*_test.go' --quiet || (echo; \ 16 | echo "Unexpected differences in acceptance test HCL content formatting."; \ 17 | echo "To see the full differences, run: terrafmt diff ./es --pattern '*_test.go'"; \ 18 | exit 1) 19 | -------------------------------------------------------------------------------- /script/wait-for-endpoint: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Waits until request to given URI returns 200 or timeout threshold is reached. 4 | # Can be given a command to run when done waiting. 5 | # 6 | # From https://github.com/cec/wait-for-endpoint/ 7 | 8 | SCRIPT_NAME=${0##*/} 9 | 10 | echoerr() { if [[ $QUIET -ne 1 ]]; then echo "$@" 1>&2; fi } 11 | 12 | usage() 13 | { 14 | cat << USAGE >&2 15 | Usage: 16 | $SCRIPT_NAME uri [-s] [-t timeout] [-- COMMAND ARGS] 17 | uri a valid http(s) URI 18 | -s | --strict Only execute COMMAND if the test succeeds 19 | -q | --quiet Don't output any status messages 20 | -t TIMEOUT | --timeout=TIMEOUT 21 | Timeout in seconds, zero for no timeout 22 | -- COMMAND ARGS Command with args to run after the test finishes 23 | USAGE 24 | exit 1 25 | } 26 | 27 | wait_for() 28 | { 29 | if [[ $TIMEOUT -gt 0 ]]; then 30 | echoerr "$SCRIPT_NAME: waiting $TIMEOUT seconds for $URI" 31 | else 32 | echoerr "$SCRIPT_NAME: waiting for $URI without a timeout" 33 | fi 34 | WAIT_START_TS=$(date +%s) 35 | while : 36 | do 37 | STATUS_CODE=$(curl --connect-timeout 2 --insecure -s -o /dev/null -w ''%{http_code}'' $URI) 38 | test "$STATUS_CODE" == "200" 39 | OUTCOME=$? 40 | if [[ $OUTCOME -eq 0 ]]; then 41 | WAIT_END_TS=$(date +%s) 42 | echoerr "$SCRIPT_NAME: $URI is alive after $((WAIT_END_TS - WAIT_START_TS)) seconds" 43 | break 44 | fi 45 | sleep 1 46 | done 47 | return $OUTCOME 48 | } 49 | 50 | # passes this script and its arguments to timeout (the script calls itself inside a timeout context) 51 | wait_for_wrapper() 52 | { 53 | # In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692 54 | if [[ $QUIET -eq 1 ]]; then 55 | timeout $BUSY_BOX_TIMEFLAG $TIMEOUT $0 $URI --quiet --child --timeout=$TIMEOUT & 56 | else 57 | timeout $BUSY_BOX_TIMEFLAG $TIMEOUT $0 $URI --child --timeout=$TIMEOUT & 58 | fi 59 | SUBPROCESS_PID=$! 60 | trap "kill -INT -$SUBPROCESS_PID" INT 61 | wait $SUBPROCESS_PID 62 | OUTCOME=$? 63 | if [[ $OUTCOME -ne 0 ]]; then 64 | echoerr "$SCRIPT_NAME: timeout occurred after waiting $TIMEOUT seconds for $URI" 65 | fi 66 | return $OUTCOME 67 | } 68 | 69 | validate_uri() 70 | { 71 | curl --connect-timeout 1 --insecure -s -o /dev/null $URI 72 | curl_exit_code=$? 73 | if [[ $curl_exit_code -eq 3 ]]; then # exit code 3 indicates an invalid URI 74 | echoerr "Error: you need to provide a VALID URI to test." 75 | usage 76 | fi 77 | } 78 | 79 | # process arguments 80 | while [[ $# -gt 0 ]] 81 | do 82 | case "$1" in 83 | http://*) 84 | URI="$1" 85 | if [[ $URI == "" ]]; then break; fi 86 | shift 1 87 | ;; 88 | https://*) 89 | URI="$1" 90 | if [[ $URI == "" ]]; then break; fi 91 | shift 1 92 | ;; 93 | --child) 94 | CHILD=1 95 | shift 1 96 | ;; 97 | -q | --quiet) 98 | QUIET=1 99 | shift 1 100 | ;; 101 | -s | --strict) 102 | STRICT=1 103 | shift 1 104 | ;; 105 | -t) 106 | TIMEOUT="$2" 107 | if [[ $TIMEOUT == "" ]]; then break; fi 108 | shift 2 109 | ;; 110 | --timeout=*) 111 | TIMEOUT="${1#*=}" 112 | shift 1 113 | ;; 114 | --) 115 | shift 116 | COMMAND=("$@") 117 | break 118 | ;; 119 | -h) 120 | usage 121 | ;; 122 | --help) 123 | usage 124 | ;; 125 | *) 126 | echoerr "Unknown argument: $1" 127 | usage 128 | ;; 129 | esac 130 | done 131 | 132 | # make sure that uri was given and is valid (by testing for curl exit code 3) 133 | if [[ "$URI" == "" ]]; then 134 | echoerr "Error: you need to provide a URI to test." 135 | usage 136 | fi 137 | validate_uri 138 | 139 | 140 | TIMEOUT=${TIMEOUT:-15} 141 | STRICT=${STRICT:-0} 142 | CHILD=${CHILD:-0} 143 | QUIET=${QUIET:-0} 144 | 145 | # Check to see if timeout is from busybox? 146 | TIMEOUT_PATH=$(type -p timeout) 147 | TIMEOUT_PATH=$(realpath $TIMEOUT_PATH 2>/dev/null || readlink -f $TIMEOUT_PATH) 148 | 149 | BUSY_BOX_TIMEFLAG="" 150 | if [[ $TIMEOUT_PATH =~ "busybox" ]]; then 151 | ON_BUSY_BOX=1 152 | # Check if busybox timeout uses -t flag 153 | # (recent Alpine versions don't support -t anymore) 154 | if timeout &>/dev/stdout | grep -q -e '-t '; then 155 | BUSY_BOX_TIMEFLAG="-t" 156 | fi 157 | else 158 | ON_BUSY_BOX=0 159 | fi 160 | 161 | if [[ $CHILD -gt 0 ]]; then 162 | wait_for 163 | OUTCOME=$? 164 | exit $OUTCOME 165 | else 166 | if [[ $TIMEOUT -gt 0 ]]; then 167 | wait_for_wrapper 168 | OUTCOME=$? 169 | else 170 | wait_for 171 | OUTCOME=$? 172 | fi 173 | fi 174 | 175 | if [[ $COMMAND != "" ]]; then 176 | if [[ $OUTCOME -ne 0 && $STRICT -eq 1 ]]; then 177 | echoerr "$SCRIPT_NAME: strict mode, refusing to execute subprocess" 178 | exit $OUTCOME 179 | fi 180 | exec "${COMMAND[@]}" 181 | else 182 | exit $OUTCOME 183 | fi 184 | -------------------------------------------------------------------------------- /test_aws_config: -------------------------------------------------------------------------------- 1 | [profile testing] 2 | aws_access_key_id = PROFILE_ACCESS_KEY 3 | aws_secret_access_key = PROFILE_SECRET_KEY 4 | -------------------------------------------------------------------------------- /tools/tools.go: -------------------------------------------------------------------------------- 1 | // +build tools 2 | 3 | package tools 4 | 5 | import ( 6 | _ "github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs" 7 | _ "github.com/katbyte/terrafmt" 8 | ) 9 | --------------------------------------------------------------------------------