diff --git a/.github/workflows/ci-checks-tf.yml b/.github/workflows/ci-checks-tf.yml new file mode 100644 index 0000000..6135c29 --- /dev/null +++ b/.github/workflows/ci-checks-tf.yml @@ -0,0 +1,66 @@ +name: ci-checks-tf + +on: + pull_request: + types: [opened, reopened, synchronize, labeled, unlabeled] + +permissions: + id-token: write + contents: write + pull-requests: write + + +jobs: + pre-commit: + runs-on: ubuntu-latest + container: ghcr.io/antonbabenko/pre-commit-terraform:v1.79.1 + steps: + - uses: actions/checkout@v3 + + - name: 'pre-commit::add-github-repo-safe' + run: | + git config --global --add safe.directory $GITHUB_WORKSPACE + + - name: 'pre-commit::run-all-checks' + run: | + pre-commit run -a --show-diff-on-failure -v + + module-required-files: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: 'tf-module::check-required-files' + id: check_files + uses: andstor/file-existence-action@v2 + with: + files: "variables.tf, main.tf, README.md, versions.tf" + fail: true + + label-required-semver: + runs-on: ubuntu-latest + steps: + - name: 'pr::check-required-semver' + uses: docker://agilepathway/pull-request-label-checker:latest + with: + prefix_mode: true + one_of: "release/" # patch , minor , major + repo_token: ${{ secrets.GITHUB_TOKEN }} + + label-required-pr-type: + runs-on: ubuntu-latest + steps: + - name: 'pr::check-required-pr-type' + uses: docker://agilepathway/pull-request-label-checker:latest + with: + any_of: bug,enhancement,documentation,security + repo_token: ${{ secrets.GITHUB_TOKEN }} + + label-do-not-merge: + runs-on: ubuntu-latest + steps: + - name: 'pr::check-required-semver' + uses: docker://agilepathway/pull-request-label-checker:latest + with: + none_of: do-not-merge + repo_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/terraform.yml b/.github/workflows/terraform.yml index 91c3c73..0ff17e0 100644 --- a/.github/workflows/terraform.yml +++ b/.github/workflows/terraform.yml @@ -46,4 +46,4 @@ jobs: - name: Check out code uses: actions/checkout@master - name: Terraform security scan - uses: triat/terraform-security-scan@v3.0.3 + uses: triat/terraform-security-scan@v3.1.0 diff --git a/.github/workflows/v1-func-create-tag-and-release.yml b/.github/workflows/v1-func-create-tag-and-release.yml new file mode 100644 index 0000000..242e0d4 --- /dev/null +++ b/.github/workflows/v1-func-create-tag-and-release.yml @@ -0,0 +1,37 @@ +name: v1-func-create-tag-and-release + +on: + pull_request: + types: [closed] + +jobs: + create-new-release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions-ecosystem/action-release-label@v1 + id: release-label + if: ${{ github.event.pull_request.merged == true }} + + - uses: actions-ecosystem/action-get-latest-tag@v1 + id: get-latest-tag + if: ${{ steps.release-label.outputs.level != null }} + + - uses: actions-ecosystem/action-bump-semver@v1 + id: bump-semver + if: ${{ steps.release-label.outputs.level != null }} + with: + current_version: ${{ steps.get-latest-tag.outputs.tag }} + level: ${{ steps.release-label.outputs.level }} + + - uses: actions-ecosystem/action-push-tag@v1 + if: ${{ steps.release-label.outputs.level != null }} + with: + tag: ${{ steps.bump-semver.outputs.new_version }} + message: '${{ steps.bump-semver.outputs.new_version }}: PR #${{ github.event.pull_request.number }} ${{ github.event.pull_request.title }}' + + - name: 'gh::release' + if: ${{ steps.release-label.outputs.level != null }} + uses: softprops/action-gh-release@v1 + with: + tag_name: ${{ steps.bump-semver.outputs.new_version }} diff --git a/.gitignore b/.gitignore index 85a0c5a..fe71332 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,7 @@ *.tfstate.* # .tfvars files -*.tfvars \ No newline at end of file +*.tfvars + +# .terraform.lock.hcl files +.terraform.local.hcl diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..898eeb6 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,7 @@ +repos: + - repo: https://github.com/antonbabenko/pre-commit-terraform + rev: v1.77.0 + hooks: + - id: terraform_fmt + - id: terraform_docs + - id: terraform_validate diff --git a/.terraform.lock.hcl b/.terraform.lock.hcl deleted file mode 100644 index d2c9649..0000000 --- a/.terraform.lock.hcl +++ /dev/null @@ -1,43 +0,0 @@ -# This file is maintained automatically by "terraform init". -# Manual edits may be lost in future updates. - -provider "registry.terraform.io/hashicorp/aws" { - version = "4.9.0" - constraints = "> 4.0.0" - hashes = [ - "h1:OWIIlbMZl/iQ8qR1U7Co3sGjNHL1HJtgNRnnV1kXNuI=", - "zh:084b83aef3335ad4f5e4b8323c6fe43c1ff55e17a7647c6a5cad6af519f72b42", - "zh:132e47ce69f14de4523b84b213cedf7173398acda14245b1ffe7747aac50f050", - "zh:2068baef7dfce3613f3b4f27314175e971f8db68d9cde9ec30b5659f80c68c6c", - "zh:63c6f489683d5f1ac55e82a0df387143ed22701d5f22c109a4d5c9924dd4e437", - "zh:8115fd21965954fa4568c09331e05bb29da967fab8d077419aed09954378e216", - "zh:8efdc95fde108f777ed9c79ae25dc17aea9771903250f5c5c8a4c726b90a345f", - "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", - "zh:9d42a7bc34d84b70c1d1bcc215cabd63abbcbd0352b70bd84da6c3916634932f", - "zh:aacbcceb241aa475888c0869e87593182edeced3170c76a0c960dd9c905df449", - "zh:c7fe7904511052e4102870256819a1917177572cf684f0611ebf767f9c1fbaa8", - "zh:c8e07c3424663d1d0e7e32f4ade8099c19f6326d37c6da98104d90c986ff66fc", - "zh:e47cafbd38b56ef14fd8d727b4ffea847c166b1c684f585ee5fb78983b537248", - ] -} - -provider "registry.terraform.io/phillbaker/elasticsearch" { - version = "2.0.0" - constraints = ">= 2.0.0" - hashes = [ - "h1:QtI7p++yuvARChuvexVO93lq6WN/tDv/dW99VsLu/WY=", - "zh:29dd759a17e60f2f514a94e862c37f4ec4bd54f997a2cec3764186e9b0c4a486", - "zh:3d168561fbb018d7c16b85ec445ef166e138fb4d6a65beae296a1dd8a93a04a2", - "zh:69cc8b76fa54185170681f4a6b426c378ac660015d80f1a0e16a75cdabbeb791", - "zh:6dc80df9ef0d1d613bbebf85425e6b51880358f8005bcc180d34960ee92f0c9d", - "zh:98e2ede8a863a85448ebd8bebccdee42b8fbe24fe84d00c1ed0c256a1f96e422", - "zh:9ba535a36d9a801e89ecc6a94e73f8dff2522620b18b2ff1b94f3e377ee63390", - "zh:a285b4966145d4afbeab3299f5cd7450cf941ed08a82171f24c879c31ad06f9c", - "zh:bdb8071b71356cb19a9520f237d3e4489329cdd17349094991c3d8323ac1d62a", - "zh:be00ff3f3513ec12d62dbfc493f9dca405d74230e48a1107f42460c49a1774c3", - "zh:c3eccfb4f9892c6ebc780a4f85ea6894d142fcbc4c6eab1f8b379aa28d572c37", - "zh:c8e292dbe829e842fbe391903422c599a68099e8c3e5e0f1f827e2c9f6d473be", - "zh:d08c01ed670ff730250b3529ac3cbff984f3537e466a793528a94eb57985c976", - "zh:e8cd83f068baf13bc8a700d3f978ed521af5f152c11d80938a3e111da503a80e", - ] -} diff --git a/example/.terraform.lock.hcl b/example/.terraform.lock.hcl deleted file mode 100644 index 1357aea..0000000 --- a/example/.terraform.lock.hcl +++ /dev/null @@ -1,43 +0,0 @@ -# This file is maintained automatically by "terraform init". -# Manual edits may be lost in future updates. - -provider "registry.terraform.io/hashicorp/aws" { - version = "4.9.0" - constraints = "> 4.0.0, >= 4.0.0" - hashes = [ - "h1:OWIIlbMZl/iQ8qR1U7Co3sGjNHL1HJtgNRnnV1kXNuI=", - "zh:084b83aef3335ad4f5e4b8323c6fe43c1ff55e17a7647c6a5cad6af519f72b42", - "zh:132e47ce69f14de4523b84b213cedf7173398acda14245b1ffe7747aac50f050", - "zh:2068baef7dfce3613f3b4f27314175e971f8db68d9cde9ec30b5659f80c68c6c", - "zh:63c6f489683d5f1ac55e82a0df387143ed22701d5f22c109a4d5c9924dd4e437", - "zh:8115fd21965954fa4568c09331e05bb29da967fab8d077419aed09954378e216", - "zh:8efdc95fde108f777ed9c79ae25dc17aea9771903250f5c5c8a4c726b90a345f", - "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", - "zh:9d42a7bc34d84b70c1d1bcc215cabd63abbcbd0352b70bd84da6c3916634932f", - "zh:aacbcceb241aa475888c0869e87593182edeced3170c76a0c960dd9c905df449", - "zh:c7fe7904511052e4102870256819a1917177572cf684f0611ebf767f9c1fbaa8", - "zh:c8e07c3424663d1d0e7e32f4ade8099c19f6326d37c6da98104d90c986ff66fc", - "zh:e47cafbd38b56ef14fd8d727b4ffea847c166b1c684f585ee5fb78983b537248", - ] -} - -provider "registry.terraform.io/phillbaker/elasticsearch" { - version = "2.0.0" - constraints = ">= 2.0.0" - hashes = [ - "h1:QtI7p++yuvARChuvexVO93lq6WN/tDv/dW99VsLu/WY=", - "zh:29dd759a17e60f2f514a94e862c37f4ec4bd54f997a2cec3764186e9b0c4a486", - "zh:3d168561fbb018d7c16b85ec445ef166e138fb4d6a65beae296a1dd8a93a04a2", - "zh:69cc8b76fa54185170681f4a6b426c378ac660015d80f1a0e16a75cdabbeb791", - "zh:6dc80df9ef0d1d613bbebf85425e6b51880358f8005bcc180d34960ee92f0c9d", - "zh:98e2ede8a863a85448ebd8bebccdee42b8fbe24fe84d00c1ed0c256a1f96e422", - "zh:9ba535a36d9a801e89ecc6a94e73f8dff2522620b18b2ff1b94f3e377ee63390", - "zh:a285b4966145d4afbeab3299f5cd7450cf941ed08a82171f24c879c31ad06f9c", - "zh:bdb8071b71356cb19a9520f237d3e4489329cdd17349094991c3d8323ac1d62a", - "zh:be00ff3f3513ec12d62dbfc493f9dca405d74230e48a1107f42460c49a1774c3", - "zh:c3eccfb4f9892c6ebc780a4f85ea6894d142fcbc4c6eab1f8b379aa28d572c37", - "zh:c8e292dbe829e842fbe391903422c599a68099e8c3e5e0f1f827e2c9f6d473be", - "zh:d08c01ed670ff730250b3529ac3cbff984f3537e466a793528a94eb57985c976", - "zh:e8cd83f068baf13bc8a700d3f978ed521af5f152c11d80938a3e111da503a80e", - ] -} diff --git a/example/main.tf b/example/main.tf index 55da29e..230bbce 100644 --- a/example/main.tf +++ b/example/main.tf @@ -1,7 +1,7 @@ data "aws_region" "current" {} provider "elasticsearch" { - url = "https://${var.cluster_name}.${var.cluster_domain_name}" + url = "https://${var.cluster_name}.${var.cluster_domain}" aws_region = data.aws_region.current.name healthcheck = false } @@ -9,9 +9,10 @@ provider "elasticsearch" { module "opensearch" { source = "../" + enabled = true + cluster_name = var.cluster_name - cluster_domain = var.cluster_domain_name - cluster_version = "OpenSearch_1.2" + cluster_version = "OpenSearch_2.7" subnet_ids = var.subnet_ids security_group_ids = var.security_group_ids @@ -21,5 +22,7 @@ module "opensearch" { ebs_enabled = true ebs_volume_size = 50 + saml_options_enabled = false + cloudwatch_log_enabled = true } diff --git a/main.tf b/main.tf index 4dcad7e..ffad22b 100644 --- a/main.tf +++ b/main.tf @@ -1,6 +1,7 @@ resource "aws_elasticsearch_domain" "opensearch" { domain_name = var.cluster_name elasticsearch_version = var.cluster_version + count = var.enabled ? 1 : 0 cluster_config { dedicated_master_enabled = var.master_instance_count > 0 @@ -14,6 +15,10 @@ resource "aws_elasticsearch_domain" "opensearch" { warm_count = var.warm_enabled ? var.warm_instance_count : null warm_type = var.warm_enabled ? var.warm_instance_type : null + cold_storage_options { + enabled = var.cold_enabled + } + zone_awareness_enabled = (var.availability_zones > 1) ? true : false zone_awareness_config { @@ -49,7 +54,9 @@ resource "aws_elasticsearch_domain" "opensearch" { enabled = true internal_user_database_enabled = var.internal_user_database_enabled master_user_options { - master_user_arn = var.master_user_arn + master_user_arn = var.internal_user_database_enabled ? var.master_user_arn : null + master_user_name = var.internal_user_database_enabled ? var.master_user_name : null + master_user_password = var.internal_user_database_enabled ? var.master_user_password : null } } @@ -89,11 +96,29 @@ resource "aws_elasticsearch_domain" "opensearch" { role_arn = var.cognito_enabled ? var.cognito_role_arn : "" } + dynamic "auto_tune_options" { + for_each = var.autotune_enabled ? [1] : [] + content { + desired_state = var.autotune_options.desired_state + rollback_on_disable = var.autotune_options.rollback_on_disable + + maintenance_schedule { + start_at = var.autotune_options.maintenance_schedule.start_at + duration { + value = var.autotune_options.maintenance_schedule.duration + unit = "HOURS" + } + cron_expression_for_recurrence = var.autotune_options.maintenance_schedule.cron_expression + } + } + } + tags = var.tags } resource "aws_elasticsearch_domain_saml_options" "opensearch_saml_options" { domain_name = var.cluster_name + count = var.saml_options_enabled ? 1 : 0 saml_options { enabled = var.saml_options_enabled master_backend_role = var.saml_options_master_backend_role diff --git a/outputs.tf b/outputs.tf index c375030..f4cf981 100644 --- a/outputs.tf +++ b/outputs.tf @@ -1,29 +1,29 @@ output "opensearch_domain_arn" { description = "Return ARN of the OpenSearch cluster domain." - value = aws_elasticsearch_domain.opensearch.arn + value = aws_elasticsearch_domain.opensearch[*].arn } output "opensearch_domain_id" { description = "The domain id of the OpenSearch cluster." - value = aws_elasticsearch_domain.opensearch.id + value = aws_elasticsearch_domain.opensearch[*].id } output "cluster_name" { description = "The name of the OpenSearch cluster." - value = aws_elasticsearch_domain.opensearch.domain_name + value = aws_elasticsearch_domain.opensearch[*].domain_name } output "cluster_endpoint" { description = "The endpoint URL of the OpenSearch cluster." - value = aws_elasticsearch_domain.opensearch.endpoint + value = aws_elasticsearch_domain.opensearch[*].endpoint } output "cluster_version" { description = "The version of the OpenSearch cluster." - value = replace(aws_elasticsearch_domain.opensearch.elasticsearch_version, "OpenSearch_", "") + value = [for i in aws_elasticsearch_domain.opensearch[*] : replace(i.elasticsearch_version, "OpenSearch_", "")] } output "kibana_endpoint" { description = "The endpoint URL of Kibana." - value = aws_elasticsearch_domain.opensearch.kibana_endpoint + value = aws_elasticsearch_domain.opensearch[*].kibana_endpoint } diff --git a/variables.tf b/variables.tf index 603b7c0..0ad8ab7 100644 --- a/variables.tf +++ b/variables.tf @@ -1,3 +1,9 @@ +variable "enabled" { + description = "Enable OpenSearch." + type = bool + default = true +} + variable "cluster_name" { description = "The name of the OpenSearch cluster." type = string @@ -58,6 +64,12 @@ variable "warm_instance_count" { default = 3 } +variable "cold_enabled" { + description = "Enable cold storage." + type = bool + default = false +} + variable "availability_zones" { description = "The number of availability zones for the OpenSearch cluster. Valid values: 1, 2 or 3." type = number @@ -152,6 +164,18 @@ variable "master_user_arn" { default = null } +variable "master_user_name" { + description = "Name of the main user." + type = string + default = null +} + +variable "master_user_password" { + description = "Password of the main user." + type = string + default = null +} + variable "encrypt_kms_key_id" { description = "KMS key id to encrypt OpenSearch domain with." type = string @@ -254,6 +278,41 @@ variable "saml_options_idp_metadata_content" { default = null } +variable "autotune_enabled" { + type = bool + description = "Enable autotune options" + default = false +} + +variable "autotune_options" { + type = object({ + desired_state = string + rollback_on_disable = string + maintenance_schedule = object({ + cron_expression = string + duration = number + start_at = string + }) + }) + default = { + desired_state = "ENABLED" + rollback_on_disable = "NO_ROLLBACK" + maintenance_schedule = { + cron_expression = "cron(0 0 ? * 1 *)" + duration = 1 + start_at = "2000-01-01T00:00:00.00Z" + } + } + validation { + condition = can(regex("^DEFAULT_ROLLBACK|NO_ROLLBACK$", var.autotune_options.rollback_on_disable)) + error_message = "Autotune rollback_on_disable should be 'DEFAULT_ROLLBACK' or 'NO_ROLLBACK'." + } + validation { + condition = can(regex("^ENABLED|DISABLED$", var.autotune_options.desired_state)) + error_message = "Autotune desired_state should be 'ENABLED' or 'DISABLED'." + } +} + variable "tags" { type = map(string) description = "A mapping of tags to assign to the OpenSearch cluster."