From 8c4728794020af671ee96a9c9b887ef25252b29a Mon Sep 17 00:00:00 2001 From: Yonatan Koren <me@yonatankoren.com> Date: Mon, 7 Jun 2021 11:30:10 -0400 Subject: [PATCH] Feat: Add Support for Integration Actions (#20) * Add support for the opsgenie_integration_action resource in both its own submodule and the config submodule. * update context.tf in example configs --- README.md | 25 ++- README.yaml | 4 + docs/terraform.md | 21 +- examples/advanced_features/api_integration.tf | 9 + examples/advanced_features/context.tf | 202 ++++++++++++++++++ examples/advanced_features/fixtures.tfvars | 4 + .../advanced_features/integration_action.tf | 26 +++ examples/advanced_features/main.tf | 3 + examples/advanced_features/outputs.tf | 24 +++ examples/advanced_features/team.tf | 9 + examples/advanced_features/variables.tf | 5 + examples/advanced_features/versions.tf | 10 + examples/alert_policy/context.tf | 67 ++++-- examples/api_integration/context.tf | 67 ++++-- examples/config/context.tf | 67 ++++-- examples/config/outputs.tf | 5 + .../config/resources/integration_actions.yaml | 13 ++ examples/escalation/context.tf | 67 ++++-- examples/integration_action/context.tf | 202 ++++++++++++++++++ examples/integration_action/fixtures.tfvars | 4 + examples/integration_action/main.tf | 48 +++++ examples/integration_action/outputs.tf | 9 + examples/integration_action/variables.tf | 5 + examples/integration_action/versions.tf | 10 + examples/notification_policy/context.tf | 67 ++++-- examples/team/context.tf | 67 ++++-- examples/team_routing_rule/context.tf | 67 ++++-- examples/user/context.tf | 67 ++++-- main.tf | 6 + modules/config/integration_actions.tf | 148 +++++++++++++ modules/config/main.tf | 1 + modules/config/outputs.tf | 7 + modules/integration_action/README.md | 57 +++++ modules/integration_action/context.tf | 202 ++++++++++++++++++ modules/integration_action/main.tf | 147 +++++++++++++ modules/integration_action/outputs.tf | 4 + modules/integration_action/variables.tf | 4 + modules/integration_action/versions.tf | 10 + outputs.tf | 5 + test/src/examples_advanced_features.go | 24 +++ test/src/examples_integration_action.go | 24 +++ variables.tf | 5 + 42 files changed, 1672 insertions(+), 146 deletions(-) create mode 100644 examples/advanced_features/api_integration.tf create mode 100644 examples/advanced_features/context.tf create mode 100644 examples/advanced_features/fixtures.tfvars create mode 100644 examples/advanced_features/integration_action.tf create mode 100644 examples/advanced_features/main.tf create mode 100644 examples/advanced_features/outputs.tf create mode 100644 examples/advanced_features/team.tf create mode 100644 examples/advanced_features/variables.tf create mode 100644 examples/advanced_features/versions.tf create mode 100644 examples/config/resources/integration_actions.yaml create mode 100644 examples/integration_action/context.tf create mode 100644 examples/integration_action/fixtures.tfvars create mode 100644 examples/integration_action/main.tf create mode 100644 examples/integration_action/outputs.tf create mode 100644 examples/integration_action/variables.tf create mode 100644 examples/integration_action/versions.tf create mode 100644 modules/config/integration_actions.tf create mode 100644 modules/integration_action/README.md create mode 100644 modules/integration_action/context.tf create mode 100644 modules/integration_action/main.tf create mode 100644 modules/integration_action/outputs.tf create mode 100644 modules/integration_action/variables.tf create mode 100644 modules/integration_action/versions.tf create mode 100644 test/src/examples_advanced_features.go create mode 100644 test/src/examples_integration_action.go diff --git a/README.md b/README.md index 85806b6..eff04a1 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,7 @@ Available modules: - [API Integration](modules/api_integration) - [Config](modules/config) - [Escalation](modules/escalation) +- [Integration Action](modules/integration_action) (advanced feature — not available to all OpsGenie plans) - [Notification Policy](modules/notification_policy) - [Team](modules/team) - [Team Routing Rule](modules/team_routing_rule) @@ -78,6 +79,8 @@ Available modules: **Note:** Root module is just an example that uses all of submodules. +**Note:** See the [Advanced Features Example](examples/advanced_features) for features only available to some OpsGenie plans. + ## Security & Compliance [<img src="https://cloudposse.com/wp-content/uploads/2020/11/bridgecrew.svg" width="250" align="right" />](https://bridgecrew.io/) @@ -140,6 +143,7 @@ Submodules examples: - [`alert_policy`](examples/alert_policy) - [`api_integration`](examples/api_integration) - [`escalation`](examples/escalation) +- [`integration_action`](examples/integration_action) (advanced feature — not available to all OpsGenie plans) - [`notification_policy`](examples/notification_policy) - [`team`](examples/team) - [`team_routing_rule`](examples/team_routing_rule) @@ -181,16 +185,17 @@ No providers. | Name | Source | Version | |------|--------|---------| -| <a name="module_alert_policy"></a> [alert\_policy](#module\_alert\_policy) | ./modules/alert_policy | | -| <a name="module_api_integration"></a> [api\_integration](#module\_api\_integration) | ./modules/api_integration | | -| <a name="module_escalation"></a> [escalation](#module\_escalation) | ./modules/escalation | | -| <a name="module_notification_policy"></a> [notification\_policy](#module\_notification\_policy) | ./modules/notification_policy | | -| <a name="module_service"></a> [service](#module\_service) | ./modules/service | | -| <a name="module_service_incident_rule"></a> [service\_incident\_rule](#module\_service\_incident\_rule) | ./modules/service_incident_rule | | -| <a name="module_team"></a> [team](#module\_team) | ./modules/team | | -| <a name="module_team_routing_rule"></a> [team\_routing\_rule](#module\_team\_routing\_rule) | ./modules/team_routing_rule | | +| <a name="module_alert_policy"></a> [alert\_policy](#module\_alert\_policy) | ./modules/alert_policy | n/a | +| <a name="module_api_integration"></a> [api\_integration](#module\_api\_integration) | ./modules/api_integration | n/a | +| <a name="module_escalation"></a> [escalation](#module\_escalation) | ./modules/escalation | n/a | +| <a name="module_integration_action"></a> [integration\_action](#module\_integration\_action) | ./modules/integration_action | n/a | +| <a name="module_notification_policy"></a> [notification\_policy](#module\_notification\_policy) | ./modules/notification_policy | n/a | +| <a name="module_service"></a> [service](#module\_service) | ./modules/service | n/a | +| <a name="module_service_incident_rule"></a> [service\_incident\_rule](#module\_service\_incident\_rule) | ./modules/service_incident_rule | n/a | +| <a name="module_team"></a> [team](#module\_team) | ./modules/team | n/a | +| <a name="module_team_routing_rule"></a> [team\_routing\_rule](#module\_team\_routing\_rule) | ./modules/team_routing_rule | n/a | | <a name="module_this"></a> [this](#module\_this) | cloudposse/label/null | 0.24.1 | -| <a name="module_user"></a> [user](#module\_user) | ./modules/user | | +| <a name="module_user"></a> [user](#module\_user) | ./modules/user | n/a | ## Resources @@ -210,6 +215,7 @@ No resources. | <a name="input_environment"></a> [environment](#input\_environment) | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | | <a name="input_escalation"></a> [escalation](#input\_escalation) | Opsgenie Escalation configuration | `map` | `{}` | no | | <a name="input_id_length_limit"></a> [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).<br>Set to `0` for unlimited length.<br>Set to `null` for default, which is `0`.<br>Does not affect `id_full`. | `number` | `null` | no | +| <a name="input_integration_action"></a> [integration\_action](#input\_integration\_action) | Opsgenie Integration Action configuration | `map` | `{}` | no | | <a name="input_label_key_case"></a> [label\_key\_case](#input\_label\_key\_case) | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.<br>Possible values: `lower`, `title`, `upper`.<br>Default value: `title`. | `string` | `null` | no | | <a name="input_label_order"></a> [label\_order](#input\_label\_order) | The naming order of the id output and Name tag.<br>Defaults to ["namespace", "environment", "stage", "name", "attributes"].<br>You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | | <a name="input_label_value_case"></a> [label\_value\_case](#input\_label\_value\_case) | The letter case of output label values (also used in `tags` and `id`).<br>Possible values: `lower`, `title`, `upper` and `none` (no transformation).<br>Default value: `lower`. | `string` | `null` | no | @@ -241,6 +247,7 @@ No resources. | <a name="output_api_integration_name"></a> [api\_integration\_name](#output\_api\_integration\_name) | The name of the Opsgenie API Integration | | <a name="output_escalation_id"></a> [escalation\_id](#output\_escalation\_id) | The ID of the Opsgenie Escalation | | <a name="output_escalation_name"></a> [escalation\_name](#output\_escalation\_name) | Name of the Opsgenie Escalation | +| <a name="output_integration_action_id"></a> [integration\_action\_id](#output\_integration\_action\_id) | The ID of the Opsgenie Integration Action | | <a name="output_notification_policy_id"></a> [notification\_policy\_id](#output\_notification\_policy\_id) | The ID of the Opsgenie Notification Policy | | <a name="output_notification_policy_name"></a> [notification\_policy\_name](#output\_notification\_policy\_name) | The name of the Opsgenie Notification Policy | | <a name="output_service_id"></a> [service\_id](#output\_service\_id) | The ID of the Opsgenie Service | diff --git a/README.yaml b/README.yaml index f057fcf..43b92b4 100644 --- a/README.yaml +++ b/README.yaml @@ -64,6 +64,7 @@ introduction: |- - [API Integration](modules/api_integration) - [Config](modules/config) - [Escalation](modules/escalation) + - [Integration Action](modules/integration_action) (advanced feature — not available to all OpsGenie plans) - [Notification Policy](modules/notification_policy) - [Team](modules/team) - [Team Routing Rule](modules/team_routing_rule) @@ -73,6 +74,8 @@ introduction: |- **Note:** Root module is just an example that uses all of submodules. + **Note:** See the [Advanced Features Example](examples/advanced_features) for features only available to some OpsGenie plans. + usage: |- Here's how to invoke `team` module in your projects @@ -99,6 +102,7 @@ examples: |- - [`alert_policy`](examples/alert_policy) - [`api_integration`](examples/api_integration) - [`escalation`](examples/escalation) + - [`integration_action`](examples/integration_action) (advanced feature — not available to all OpsGenie plans) - [`notification_policy`](examples/notification_policy) - [`team`](examples/team) - [`team_routing_rule`](examples/team_routing_rule) diff --git a/docs/terraform.md b/docs/terraform.md index b99b2f8..0262a3d 100644 --- a/docs/terraform.md +++ b/docs/terraform.md @@ -14,16 +14,17 @@ No providers. | Name | Source | Version | |------|--------|---------| -| <a name="module_alert_policy"></a> [alert\_policy](#module\_alert\_policy) | ./modules/alert_policy | | -| <a name="module_api_integration"></a> [api\_integration](#module\_api\_integration) | ./modules/api_integration | | -| <a name="module_escalation"></a> [escalation](#module\_escalation) | ./modules/escalation | | -| <a name="module_notification_policy"></a> [notification\_policy](#module\_notification\_policy) | ./modules/notification_policy | | -| <a name="module_service"></a> [service](#module\_service) | ./modules/service | | -| <a name="module_service_incident_rule"></a> [service\_incident\_rule](#module\_service\_incident\_rule) | ./modules/service_incident_rule | | -| <a name="module_team"></a> [team](#module\_team) | ./modules/team | | -| <a name="module_team_routing_rule"></a> [team\_routing\_rule](#module\_team\_routing\_rule) | ./modules/team_routing_rule | | +| <a name="module_alert_policy"></a> [alert\_policy](#module\_alert\_policy) | ./modules/alert_policy | n/a | +| <a name="module_api_integration"></a> [api\_integration](#module\_api\_integration) | ./modules/api_integration | n/a | +| <a name="module_escalation"></a> [escalation](#module\_escalation) | ./modules/escalation | n/a | +| <a name="module_integration_action"></a> [integration\_action](#module\_integration\_action) | ./modules/integration_action | n/a | +| <a name="module_notification_policy"></a> [notification\_policy](#module\_notification\_policy) | ./modules/notification_policy | n/a | +| <a name="module_service"></a> [service](#module\_service) | ./modules/service | n/a | +| <a name="module_service_incident_rule"></a> [service\_incident\_rule](#module\_service\_incident\_rule) | ./modules/service_incident_rule | n/a | +| <a name="module_team"></a> [team](#module\_team) | ./modules/team | n/a | +| <a name="module_team_routing_rule"></a> [team\_routing\_rule](#module\_team\_routing\_rule) | ./modules/team_routing_rule | n/a | | <a name="module_this"></a> [this](#module\_this) | cloudposse/label/null | 0.24.1 | -| <a name="module_user"></a> [user](#module\_user) | ./modules/user | | +| <a name="module_user"></a> [user](#module\_user) | ./modules/user | n/a | ## Resources @@ -43,6 +44,7 @@ No resources. | <a name="input_environment"></a> [environment](#input\_environment) | Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no | | <a name="input_escalation"></a> [escalation](#input\_escalation) | Opsgenie Escalation configuration | `map` | `{}` | no | | <a name="input_id_length_limit"></a> [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).<br>Set to `0` for unlimited length.<br>Set to `null` for default, which is `0`.<br>Does not affect `id_full`. | `number` | `null` | no | +| <a name="input_integration_action"></a> [integration\_action](#input\_integration\_action) | Opsgenie Integration Action configuration | `map` | `{}` | no | | <a name="input_label_key_case"></a> [label\_key\_case](#input\_label\_key\_case) | The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`.<br>Possible values: `lower`, `title`, `upper`.<br>Default value: `title`. | `string` | `null` | no | | <a name="input_label_order"></a> [label\_order](#input\_label\_order) | The naming order of the id output and Name tag.<br>Defaults to ["namespace", "environment", "stage", "name", "attributes"].<br>You can omit any of the 5 elements, but at least one must be present. | `list(string)` | `null` | no | | <a name="input_label_value_case"></a> [label\_value\_case](#input\_label\_value\_case) | The letter case of output label values (also used in `tags` and `id`).<br>Possible values: `lower`, `title`, `upper` and `none` (no transformation).<br>Default value: `lower`. | `string` | `null` | no | @@ -74,6 +76,7 @@ No resources. | <a name="output_api_integration_name"></a> [api\_integration\_name](#output\_api\_integration\_name) | The name of the Opsgenie API Integration | | <a name="output_escalation_id"></a> [escalation\_id](#output\_escalation\_id) | The ID of the Opsgenie Escalation | | <a name="output_escalation_name"></a> [escalation\_name](#output\_escalation\_name) | Name of the Opsgenie Escalation | +| <a name="output_integration_action_id"></a> [integration\_action\_id](#output\_integration\_action\_id) | The ID of the Opsgenie Integration Action | | <a name="output_notification_policy_id"></a> [notification\_policy\_id](#output\_notification\_policy\_id) | The ID of the Opsgenie Notification Policy | | <a name="output_notification_policy_name"></a> [notification\_policy\_name](#output\_notification\_policy\_name) | The name of the Opsgenie Notification Policy | | <a name="output_service_id"></a> [service\_id](#output\_service\_id) | The ID of the Opsgenie Service | diff --git a/examples/advanced_features/api_integration.tf b/examples/advanced_features/api_integration.tf new file mode 100644 index 0000000..3a9b8e1 --- /dev/null +++ b/examples/advanced_features/api_integration.tf @@ -0,0 +1,9 @@ +module "api_integration" { + source = "../../modules/api_integration" + + api_integration = { + name = module.this.id + type = "AmazonSns" + owner_team_id = module.team.team_id + } +} diff --git a/examples/advanced_features/context.tf b/examples/advanced_features/context.tf new file mode 100644 index 0000000..81f99b4 --- /dev/null +++ b/examples/advanced_features/context.tf @@ -0,0 +1,202 @@ +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.<var>`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "cloudposse/label/null" + version = "0.24.1" # requires Terraform >= 0.13.0 + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/examples/advanced_features/fixtures.tfvars b/examples/advanced_features/fixtures.tfvars new file mode 100644 index 0000000..2660254 --- /dev/null +++ b/examples/advanced_features/fixtures.tfvars @@ -0,0 +1,4 @@ +enabled = true +namespace = "eg" +name = "incident-management-workflow" +stage = "test" diff --git a/examples/advanced_features/integration_action.tf b/examples/advanced_features/integration_action.tf new file mode 100644 index 0000000..6c72641 --- /dev/null +++ b/examples/advanced_features/integration_action.tf @@ -0,0 +1,26 @@ +module "integration_action" { + source = "../../modules/integration_action" + + integration_action = { + integration_id = module.api_integration.api_integration_id + team_id = module.team.team_id + + create = [ + { + name = "Create Non-informational Alerts" + alias = "{{title}}" + filter = { + type = "match-all-conditions" + conditions = [ + { + field = "priority" + not = true + operation = "equals" + expected_value = "P5" + } + ] + } + } + ] + } +} diff --git a/examples/advanced_features/main.tf b/examples/advanced_features/main.tf new file mode 100644 index 0000000..5ca8574 --- /dev/null +++ b/examples/advanced_features/main.tf @@ -0,0 +1,3 @@ +provider "opsgenie" { + api_key = var.opsgenie_provider_api_key +} diff --git a/examples/advanced_features/outputs.tf b/examples/advanced_features/outputs.tf new file mode 100644 index 0000000..9e59880 --- /dev/null +++ b/examples/advanced_features/outputs.tf @@ -0,0 +1,24 @@ +output "integration_action_id" { + description = "The ID of the Opsgenie Integration Action" + value = module.integration_action.integration_action_id +} + +output "api_integration_id" { + description = "The ID of the Opsgenie integration" + value = module.api_integration.api_integration_id +} + +output "api_integration_name" { + description = "The name of the Opsgenie integration" + value = module.api_integration.api_integration_name +} + +output "team_id" { + description = "The ID of the Opsgenie team" + value = module.team.team_id +} + +output "team_name" { + description = "The name of the Opsgenie team" + value = module.team.team_name +} diff --git a/examples/advanced_features/team.tf b/examples/advanced_features/team.tf new file mode 100644 index 0000000..d160a38 --- /dev/null +++ b/examples/advanced_features/team.tf @@ -0,0 +1,9 @@ +module "team" { + source = "../../modules/team" + + team = { + name = "${module.this.id}.security" + description = "${module.this.id} Security Team" + ignore_members = false + } +} diff --git a/examples/advanced_features/variables.tf b/examples/advanced_features/variables.tf new file mode 100644 index 0000000..841a369 --- /dev/null +++ b/examples/advanced_features/variables.tf @@ -0,0 +1,5 @@ +variable "opsgenie_provider_api_key" { + type = string + description = "The API Key for the Opsgenie Integration. If omitted, the OPSGENIE_API_KEY environment variable is used" + default = null +} diff --git a/examples/advanced_features/versions.tf b/examples/advanced_features/versions.tf new file mode 100644 index 0000000..240bbd5 --- /dev/null +++ b/examples/advanced_features/versions.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 0.13.0" + + required_providers { + opsgenie = { + source = "opsgenie/opsgenie" + version = ">= 0.4" + } + } +} diff --git a/examples/alert_policy/context.tf b/examples/alert_policy/context.tf index bae0cf1..81f99b4 100644 --- a/examples/alert_policy/context.tf +++ b/examples/alert_policy/context.tf @@ -19,7 +19,8 @@ # module "this" { - source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=tags/0.19.2" + source = "cloudposse/label/null" + version = "0.24.1" # requires Terraform >= 0.13.0 enabled = var.enabled namespace = var.namespace @@ -33,6 +34,8 @@ module "this" { label_order = var.label_order regex_replace_chars = var.regex_replace_chars id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case context = var.context } @@ -40,20 +43,7 @@ module "this" { # Copy contents of cloudposse/terraform-null-label/variables.tf here variable "context" { - type = object({ - enabled = bool - namespace = string - environment = string - stage = string - name = string - delimiter = string - attributes = list(string) - tags = map(string) - additional_tag_map = map(string) - regex_replace_chars = string - label_order = list(string) - id_length_limit = number - }) + type = any default = { enabled = true namespace = null @@ -67,6 +57,8 @@ variable "context" { regex_replace_chars = null label_order = [] id_length_limit = null + label_key_case = null + label_value_case = null } description = <<-EOT Single object for setting entire context at once. @@ -75,6 +67,16 @@ variable "context" { Individual variable settings (non-null) override settings in context object, except for attributes, tags, and additional_tag_map, which are merged. EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } } variable "enabled" { @@ -157,11 +159,44 @@ variable "id_length_limit" { type = number default = null description = <<-EOT - Limit `id` to this many characters. + Limit `id` to this many characters (minimum 6). Set to `0` for unlimited length. Set to `null` for default, which is `0`. Does not affect `id_full`. EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } } +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} #### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/examples/api_integration/context.tf b/examples/api_integration/context.tf index bae0cf1..81f99b4 100644 --- a/examples/api_integration/context.tf +++ b/examples/api_integration/context.tf @@ -19,7 +19,8 @@ # module "this" { - source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=tags/0.19.2" + source = "cloudposse/label/null" + version = "0.24.1" # requires Terraform >= 0.13.0 enabled = var.enabled namespace = var.namespace @@ -33,6 +34,8 @@ module "this" { label_order = var.label_order regex_replace_chars = var.regex_replace_chars id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case context = var.context } @@ -40,20 +43,7 @@ module "this" { # Copy contents of cloudposse/terraform-null-label/variables.tf here variable "context" { - type = object({ - enabled = bool - namespace = string - environment = string - stage = string - name = string - delimiter = string - attributes = list(string) - tags = map(string) - additional_tag_map = map(string) - regex_replace_chars = string - label_order = list(string) - id_length_limit = number - }) + type = any default = { enabled = true namespace = null @@ -67,6 +57,8 @@ variable "context" { regex_replace_chars = null label_order = [] id_length_limit = null + label_key_case = null + label_value_case = null } description = <<-EOT Single object for setting entire context at once. @@ -75,6 +67,16 @@ variable "context" { Individual variable settings (non-null) override settings in context object, except for attributes, tags, and additional_tag_map, which are merged. EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } } variable "enabled" { @@ -157,11 +159,44 @@ variable "id_length_limit" { type = number default = null description = <<-EOT - Limit `id` to this many characters. + Limit `id` to this many characters (minimum 6). Set to `0` for unlimited length. Set to `null` for default, which is `0`. Does not affect `id_full`. EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } } +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} #### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/examples/config/context.tf b/examples/config/context.tf index bae0cf1..81f99b4 100644 --- a/examples/config/context.tf +++ b/examples/config/context.tf @@ -19,7 +19,8 @@ # module "this" { - source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=tags/0.19.2" + source = "cloudposse/label/null" + version = "0.24.1" # requires Terraform >= 0.13.0 enabled = var.enabled namespace = var.namespace @@ -33,6 +34,8 @@ module "this" { label_order = var.label_order regex_replace_chars = var.regex_replace_chars id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case context = var.context } @@ -40,20 +43,7 @@ module "this" { # Copy contents of cloudposse/terraform-null-label/variables.tf here variable "context" { - type = object({ - enabled = bool - namespace = string - environment = string - stage = string - name = string - delimiter = string - attributes = list(string) - tags = map(string) - additional_tag_map = map(string) - regex_replace_chars = string - label_order = list(string) - id_length_limit = number - }) + type = any default = { enabled = true namespace = null @@ -67,6 +57,8 @@ variable "context" { regex_replace_chars = null label_order = [] id_length_limit = null + label_key_case = null + label_value_case = null } description = <<-EOT Single object for setting entire context at once. @@ -75,6 +67,16 @@ variable "context" { Individual variable settings (non-null) override settings in context object, except for attributes, tags, and additional_tag_map, which are merged. EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } } variable "enabled" { @@ -157,11 +159,44 @@ variable "id_length_limit" { type = number default = null description = <<-EOT - Limit `id` to this many characters. + Limit `id` to this many characters (minimum 6). Set to `0` for unlimited length. Set to `null` for default, which is `0`. Does not affect `id_full`. EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } } +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} #### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/examples/config/outputs.tf b/examples/config/outputs.tf index d34387c..e4efa8e 100644 --- a/examples/config/outputs.tf +++ b/examples/config/outputs.tf @@ -13,6 +13,11 @@ output "escalations" { description = "Escalations" } +output "integration_actions" { + value = module.opsgenie_config.integration_actions + description = "Integration Actions" +} + output "notification_policies" { value = module.opsgenie_config.notification_policies description = "Notification policies" diff --git a/examples/config/resources/integration_actions.yaml b/examples/config/resources/integration_actions.yaml new file mode 100644 index 0000000..7f1896a --- /dev/null +++ b/examples/config/resources/integration_actions.yaml @@ -0,0 +1,13 @@ +integration_actions: + - name: acme-dev-opsgenie-sns-close-low-priority + integration_name: acme-dev-opsgenie-sns-integration + create: + - name: Create Non-informational Alerts + alias: "{{title}}" + filter: + type: match-all-conditions + conditions: + - field: priority + not: true + operation: equals + expected_value: P5 diff --git a/examples/escalation/context.tf b/examples/escalation/context.tf index bae0cf1..81f99b4 100644 --- a/examples/escalation/context.tf +++ b/examples/escalation/context.tf @@ -19,7 +19,8 @@ # module "this" { - source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=tags/0.19.2" + source = "cloudposse/label/null" + version = "0.24.1" # requires Terraform >= 0.13.0 enabled = var.enabled namespace = var.namespace @@ -33,6 +34,8 @@ module "this" { label_order = var.label_order regex_replace_chars = var.regex_replace_chars id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case context = var.context } @@ -40,20 +43,7 @@ module "this" { # Copy contents of cloudposse/terraform-null-label/variables.tf here variable "context" { - type = object({ - enabled = bool - namespace = string - environment = string - stage = string - name = string - delimiter = string - attributes = list(string) - tags = map(string) - additional_tag_map = map(string) - regex_replace_chars = string - label_order = list(string) - id_length_limit = number - }) + type = any default = { enabled = true namespace = null @@ -67,6 +57,8 @@ variable "context" { regex_replace_chars = null label_order = [] id_length_limit = null + label_key_case = null + label_value_case = null } description = <<-EOT Single object for setting entire context at once. @@ -75,6 +67,16 @@ variable "context" { Individual variable settings (non-null) override settings in context object, except for attributes, tags, and additional_tag_map, which are merged. EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } } variable "enabled" { @@ -157,11 +159,44 @@ variable "id_length_limit" { type = number default = null description = <<-EOT - Limit `id` to this many characters. + Limit `id` to this many characters (minimum 6). Set to `0` for unlimited length. Set to `null` for default, which is `0`. Does not affect `id_full`. EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } } +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} #### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/examples/integration_action/context.tf b/examples/integration_action/context.tf new file mode 100644 index 0000000..81f99b4 --- /dev/null +++ b/examples/integration_action/context.tf @@ -0,0 +1,202 @@ +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.<var>`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "cloudposse/label/null" + version = "0.24.1" # requires Terraform >= 0.13.0 + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/examples/integration_action/fixtures.tfvars b/examples/integration_action/fixtures.tfvars new file mode 100644 index 0000000..83719e9 --- /dev/null +++ b/examples/integration_action/fixtures.tfvars @@ -0,0 +1,4 @@ +enabled = true +namespace = "eg" +name = "integration" +stage = "test" diff --git a/examples/integration_action/main.tf b/examples/integration_action/main.tf new file mode 100644 index 0000000..bf94fb1 --- /dev/null +++ b/examples/integration_action/main.tf @@ -0,0 +1,48 @@ +provider "opsgenie" { + api_key = var.opsgenie_provider_api_key +} + +module "team" { + source = "../../modules/team" + + team = { + name = module.this.id + } +} + +module "api_integration" { + source = "../../modules/api_integration" + + api_integration = { + name = module.this.id + type = "AmazonSns" + owner_team_id = module.team.team_id + } +} + +module "integration_action" { + source = "../../modules/integration_action" + + integration_action = { + integration_id = module.api_integration.api_integration_id + team_id = module.team.team_id + + create = [ + { + name = "Create Non-informational Alerts" + alias = "{{title}}" + filter = { + type = "match-all-conditions" + conditions = [ + { + field = "priority" + not = true + operation = "equals" + expected_value = "P5" + } + ] + } + } + ] + } +} diff --git a/examples/integration_action/outputs.tf b/examples/integration_action/outputs.tf new file mode 100644 index 0000000..e4e6b5c --- /dev/null +++ b/examples/integration_action/outputs.tf @@ -0,0 +1,9 @@ +output "integration_action" { + description = "Opsgenie Integration Action" + value = module.integration_action +} + +output "integration_action_id" { + description = "The ID of the Opsgenie Integration Action" + value = module.integration_action.integration_action_id +} diff --git a/examples/integration_action/variables.tf b/examples/integration_action/variables.tf new file mode 100644 index 0000000..841a369 --- /dev/null +++ b/examples/integration_action/variables.tf @@ -0,0 +1,5 @@ +variable "opsgenie_provider_api_key" { + type = string + description = "The API Key for the Opsgenie Integration. If omitted, the OPSGENIE_API_KEY environment variable is used" + default = null +} diff --git a/examples/integration_action/versions.tf b/examples/integration_action/versions.tf new file mode 100644 index 0000000..240bbd5 --- /dev/null +++ b/examples/integration_action/versions.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 0.13.0" + + required_providers { + opsgenie = { + source = "opsgenie/opsgenie" + version = ">= 0.4" + } + } +} diff --git a/examples/notification_policy/context.tf b/examples/notification_policy/context.tf index bae0cf1..81f99b4 100644 --- a/examples/notification_policy/context.tf +++ b/examples/notification_policy/context.tf @@ -19,7 +19,8 @@ # module "this" { - source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=tags/0.19.2" + source = "cloudposse/label/null" + version = "0.24.1" # requires Terraform >= 0.13.0 enabled = var.enabled namespace = var.namespace @@ -33,6 +34,8 @@ module "this" { label_order = var.label_order regex_replace_chars = var.regex_replace_chars id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case context = var.context } @@ -40,20 +43,7 @@ module "this" { # Copy contents of cloudposse/terraform-null-label/variables.tf here variable "context" { - type = object({ - enabled = bool - namespace = string - environment = string - stage = string - name = string - delimiter = string - attributes = list(string) - tags = map(string) - additional_tag_map = map(string) - regex_replace_chars = string - label_order = list(string) - id_length_limit = number - }) + type = any default = { enabled = true namespace = null @@ -67,6 +57,8 @@ variable "context" { regex_replace_chars = null label_order = [] id_length_limit = null + label_key_case = null + label_value_case = null } description = <<-EOT Single object for setting entire context at once. @@ -75,6 +67,16 @@ variable "context" { Individual variable settings (non-null) override settings in context object, except for attributes, tags, and additional_tag_map, which are merged. EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } } variable "enabled" { @@ -157,11 +159,44 @@ variable "id_length_limit" { type = number default = null description = <<-EOT - Limit `id` to this many characters. + Limit `id` to this many characters (minimum 6). Set to `0` for unlimited length. Set to `null` for default, which is `0`. Does not affect `id_full`. EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } } +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} #### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/examples/team/context.tf b/examples/team/context.tf index bae0cf1..81f99b4 100644 --- a/examples/team/context.tf +++ b/examples/team/context.tf @@ -19,7 +19,8 @@ # module "this" { - source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=tags/0.19.2" + source = "cloudposse/label/null" + version = "0.24.1" # requires Terraform >= 0.13.0 enabled = var.enabled namespace = var.namespace @@ -33,6 +34,8 @@ module "this" { label_order = var.label_order regex_replace_chars = var.regex_replace_chars id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case context = var.context } @@ -40,20 +43,7 @@ module "this" { # Copy contents of cloudposse/terraform-null-label/variables.tf here variable "context" { - type = object({ - enabled = bool - namespace = string - environment = string - stage = string - name = string - delimiter = string - attributes = list(string) - tags = map(string) - additional_tag_map = map(string) - regex_replace_chars = string - label_order = list(string) - id_length_limit = number - }) + type = any default = { enabled = true namespace = null @@ -67,6 +57,8 @@ variable "context" { regex_replace_chars = null label_order = [] id_length_limit = null + label_key_case = null + label_value_case = null } description = <<-EOT Single object for setting entire context at once. @@ -75,6 +67,16 @@ variable "context" { Individual variable settings (non-null) override settings in context object, except for attributes, tags, and additional_tag_map, which are merged. EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } } variable "enabled" { @@ -157,11 +159,44 @@ variable "id_length_limit" { type = number default = null description = <<-EOT - Limit `id` to this many characters. + Limit `id` to this many characters (minimum 6). Set to `0` for unlimited length. Set to `null` for default, which is `0`. Does not affect `id_full`. EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } } +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} #### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/examples/team_routing_rule/context.tf b/examples/team_routing_rule/context.tf index bae0cf1..81f99b4 100644 --- a/examples/team_routing_rule/context.tf +++ b/examples/team_routing_rule/context.tf @@ -19,7 +19,8 @@ # module "this" { - source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=tags/0.19.2" + source = "cloudposse/label/null" + version = "0.24.1" # requires Terraform >= 0.13.0 enabled = var.enabled namespace = var.namespace @@ -33,6 +34,8 @@ module "this" { label_order = var.label_order regex_replace_chars = var.regex_replace_chars id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case context = var.context } @@ -40,20 +43,7 @@ module "this" { # Copy contents of cloudposse/terraform-null-label/variables.tf here variable "context" { - type = object({ - enabled = bool - namespace = string - environment = string - stage = string - name = string - delimiter = string - attributes = list(string) - tags = map(string) - additional_tag_map = map(string) - regex_replace_chars = string - label_order = list(string) - id_length_limit = number - }) + type = any default = { enabled = true namespace = null @@ -67,6 +57,8 @@ variable "context" { regex_replace_chars = null label_order = [] id_length_limit = null + label_key_case = null + label_value_case = null } description = <<-EOT Single object for setting entire context at once. @@ -75,6 +67,16 @@ variable "context" { Individual variable settings (non-null) override settings in context object, except for attributes, tags, and additional_tag_map, which are merged. EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } } variable "enabled" { @@ -157,11 +159,44 @@ variable "id_length_limit" { type = number default = null description = <<-EOT - Limit `id` to this many characters. + Limit `id` to this many characters (minimum 6). Set to `0` for unlimited length. Set to `null` for default, which is `0`. Does not affect `id_full`. EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } } +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} #### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/examples/user/context.tf b/examples/user/context.tf index bae0cf1..81f99b4 100644 --- a/examples/user/context.tf +++ b/examples/user/context.tf @@ -19,7 +19,8 @@ # module "this" { - source = "git::https://github.com/cloudposse/terraform-null-label.git?ref=tags/0.19.2" + source = "cloudposse/label/null" + version = "0.24.1" # requires Terraform >= 0.13.0 enabled = var.enabled namespace = var.namespace @@ -33,6 +34,8 @@ module "this" { label_order = var.label_order regex_replace_chars = var.regex_replace_chars id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case context = var.context } @@ -40,20 +43,7 @@ module "this" { # Copy contents of cloudposse/terraform-null-label/variables.tf here variable "context" { - type = object({ - enabled = bool - namespace = string - environment = string - stage = string - name = string - delimiter = string - attributes = list(string) - tags = map(string) - additional_tag_map = map(string) - regex_replace_chars = string - label_order = list(string) - id_length_limit = number - }) + type = any default = { enabled = true namespace = null @@ -67,6 +57,8 @@ variable "context" { regex_replace_chars = null label_order = [] id_length_limit = null + label_key_case = null + label_value_case = null } description = <<-EOT Single object for setting entire context at once. @@ -75,6 +67,16 @@ variable "context" { Individual variable settings (non-null) override settings in context object, except for attributes, tags, and additional_tag_map, which are merged. EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } } variable "enabled" { @@ -157,11 +159,44 @@ variable "id_length_limit" { type = number default = null description = <<-EOT - Limit `id` to this many characters. + Limit `id` to this many characters (minimum 6). Set to `0` for unlimited length. Set to `null` for default, which is `0`. Does not affect `id_full`. EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } } +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} #### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/main.tf b/main.tf index 030e551..c766d3c 100644 --- a/main.tf +++ b/main.tf @@ -20,6 +20,12 @@ module "escalation" { escalation = var.escalation } +module "integration_action" { + source = "./modules/integration_action" + + integration_action = var.integration_action +} + module "notification_policy" { source = "./modules/notification_policy" diff --git a/modules/config/integration_actions.tf b/modules/config/integration_actions.tf new file mode 100644 index 0000000..2624f14 --- /dev/null +++ b/modules/config/integration_actions.tf @@ -0,0 +1,148 @@ +resource "opsgenie_integration_action" "this" { + for_each = module.this.enabled ? { for integration_action in local.integration_actions : integration_action.name => integration_action } : {} + + # Look up our integration id by name + integration_id = try(opsgenie_api_integration.this[each.value.integration_name].id, null) + + dynamic "create" { + for_each = try(each.value.create, []) + + content { + name = try(create.value.name, null) + order = try(create.value.order, null) + tags = try(create.value.tags, []) + user = try(create.value.user, null) + note = try(create.value.note, null) + alias = try(create.value.alias, null) + source = try(create.value.source, null) + message = try(create.value.message, null) + description = try(create.value.description, null) + entity = try(create.value.entity, null) + alert_actions = try(create.value.alert_actions, []) + extra_properties = try(create.value.extra_properties, {}) + custom_priority = try(create.value.custom_priority, null) + ignore_responders_from_payload = try(create.value.ignore_responders_from_payload, false) + ignore_teams_from_payload = try(create.value.ignore_teams_from_payload, false) + + responders { + id = try(opsgenie_api_integration.this[each.value.integration_name].owner_team_id, null) + type = "team" + } + + filter { + type = try(create.value.filter.type, null) + + dynamic "conditions" { + for_each = try(create.value.filter.conditions, []) + + content { + field = try(conditions.value.field, null) + not = try(conditions.value.not, null) + operation = try(conditions.value.operation, null) + expected_value = try(conditions.value.expected_value, null) + } + } + } + } + } + + dynamic "close" { + for_each = try(each.value.close, []) + + content { + name = try(close.value.name, null) + order = try(close.value.order, null) + alias = try(close.value.alias, null) + + filter { + type = try(close.value.filter.type, null) + + dynamic "conditions" { + for_each = try(close.value.filter.conditions, []) + + content { + field = try(conditions.value.field, null) + not = try(conditions.value.not, null) + operation = try(conditions.value.operation, null) + expected_value = try(conditions.value.expected_value, null) + } + } + } + } + } + + dynamic "acknowledge" { + for_each = try(each.value.acknowledge, []) + + content { + name = try(acknowledge.value.name, null) + order = try(acknowledge.value.order, null) + alias = try(acknowledge.value.alias, null) + + filter { + type = try(acknowledge.value.filter.type, null) + + dynamic "conditions" { + for_each = try(acknowledge.value.filter.conditions, []) + + content { + field = try(conditions.value.field, null) + not = try(conditions.value.not, null) + operation = try(conditions.value.operation, null) + expected_value = try(conditions.value.expected_value, null) + } + } + } + } + } + + dynamic "add_note" { + for_each = try(each.value.add_note, []) + + content { + name = try(add_note.value.name, null) + order = try(add_note.value.order, null) + alias = try(add_note.value.alias, null) + note = try(add_note.value.name, null) + + filter { + type = try(add_note.value.filter.type, null) + + dynamic "conditions" { + for_each = try(add_note.value.filter.conditions, []) + + content { + field = try(conditions.value.field, null) + not = try(conditions.value.not, null) + operation = try(conditions.value.operation, null) + expected_value = try(conditions.value.expected_value, null) + } + } + } + } + } + + dynamic "ignore" { + for_each = try(each.value.ignore, []) + + content { + name = try(ignore.value.name, null) + order = try(ignore.value.order, null) + + filter { + type = try(ignore.value.filter.type, null) + + dynamic "conditions" { + for_each = try(ignore.value.filter.conditions, []) + + content { + field = try(conditions.value.field, null) + not = try(conditions.value.not, null) + operation = try(conditions.value.operation, null) + expected_value = try(conditions.value.expected_value, null) + } + } + } + } + } +} diff --git a/modules/config/main.tf b/modules/config/main.tf index 1b368f2..4795126 100644 --- a/modules/config/main.tf +++ b/modules/config/main.tf @@ -2,6 +2,7 @@ locals { alert_policies = lookup(var.opsgenie_resources, "alert_policies", []) api_integrations = lookup(var.opsgenie_resources, "api_integrations", []) escalations = lookup(var.opsgenie_resources, "escalations", []) + integration_actions = lookup(var.opsgenie_resources, "integration_actions", []) notification_policies = lookup(var.opsgenie_resources, "notification_policies", []) team_routing_rules = lookup(var.opsgenie_resources, "team_routing_rules", []) teams = lookup(var.opsgenie_resources, "teams", []) diff --git a/modules/config/outputs.tf b/modules/config/outputs.tf index 4cc8927..4b9e726 100644 --- a/modules/config/outputs.tf +++ b/modules/config/outputs.tf @@ -27,6 +27,13 @@ output "escalations" { description = "Escalations" } +output "integration_actions" { + value = [ + for integration_action in opsgenie_integration_action.this : integration_action.id + ] + description = "Integration Actions" +} + output "notification_policies" { value = { for policy in opsgenie_notification_policy.this : policy.id => policy.name diff --git a/modules/integration_action/README.md b/modules/integration_action/README.md new file mode 100644 index 0000000..9746afb --- /dev/null +++ b/modules/integration_action/README.md @@ -0,0 +1,57 @@ +## Integration Action + +Terraform module to configure [Opsgenie Integration Action](https://registry.terraform.io/providers/opsgenie/opsgenie/latest/docs/resources/integration_action) + +NOTE: your OpsGenie plan must support advanced integrations. Otherwise, you will get the following error back from the API: `Your plan does not allow saving advanced integrations.`. + + +## Usage + +[Create Opsgenie Integration Action example](../../examples/integration_action) + +```hcl +module "integration_action" { + source = "cloudposse/incident-management/opsgenie//modules/integration_action" + # Cloud Posse recommends pinning every module to a specific version + # version = "x.x.x" + + integration_action = { + integration_id = module.api_integration.api_integration_id + + create = [ + { + name = "Create Non-informational Alerts" + alias = "{{title}}" + filter = { + type = "match-all-conditions" + conditions = [ + { + field = "priority" + not = true + operation = "equals" + expected_value = "P5" + } + ] + } + } + ] + } +} +``` + +## Inputs + +**Note:** `integration_action` is a map for two reasons: +- to be able to put whole configuration in yaml file +- variables defined with type set are not robust enough (can't set default values) + +| Name | Default | Description | Required | +|:-------------------------------|:---------------------------------:|:--------------------------------------------------------------------------------------------------------------------------------|:--------:| +| `integration_action` | `{}` | This variable is used to configure Opsgenie Integration Action. | Yes | + + +## Outputs + +| Name | Description | +|:----------------------------|:---------------------------------------------| +| `integration_action_id` | The ID of the Opsgenie Integration Action. | diff --git a/modules/integration_action/context.tf b/modules/integration_action/context.tf new file mode 100644 index 0000000..81f99b4 --- /dev/null +++ b/modules/integration_action/context.tf @@ -0,0 +1,202 @@ +# +# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label +# All other instances of this file should be a copy of that one +# +# +# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf +# and then place it in your Terraform module to automatically get +# Cloud Posse's standard configuration inputs suitable for passing +# to Cloud Posse modules. +# +# Modules should access the whole context as `module.this.context` +# to get the input variables with nulls for defaults, +# for example `context = module.this.context`, +# and access individual variables as `module.this.<var>`, +# with final values filled in. +# +# For example, when using defaults, `module.this.context.delimiter` +# will be null, and `module.this.delimiter` will be `-` (hyphen). +# + +module "this" { + source = "cloudposse/label/null" + version = "0.24.1" # requires Terraform >= 0.13.0 + + enabled = var.enabled + namespace = var.namespace + environment = var.environment + stage = var.stage + name = var.name + delimiter = var.delimiter + attributes = var.attributes + tags = var.tags + additional_tag_map = var.additional_tag_map + label_order = var.label_order + regex_replace_chars = var.regex_replace_chars + id_length_limit = var.id_length_limit + label_key_case = var.label_key_case + label_value_case = var.label_value_case + + context = var.context +} + +# Copy contents of cloudposse/terraform-null-label/variables.tf here + +variable "context" { + type = any + default = { + enabled = true + namespace = null + environment = null + stage = null + name = null + delimiter = null + attributes = [] + tags = {} + additional_tag_map = {} + regex_replace_chars = null + label_order = [] + id_length_limit = null + label_key_case = null + label_value_case = null + } + description = <<-EOT + Single object for setting entire context at once. + See description of individual variables for details. + Leave string and numeric variables as `null` to use default value. + Individual variable settings (non-null) override settings in context object, + except for attributes, tags, and additional_tag_map, which are merged. + EOT + + validation { + condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`." + } + + validation { + condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} + +variable "enabled" { + type = bool + default = null + description = "Set to false to prevent the module from creating any resources" +} + +variable "namespace" { + type = string + default = null + description = "Namespace, which could be your organization name or abbreviation, e.g. 'eg' or 'cp'" +} + +variable "environment" { + type = string + default = null + description = "Environment, e.g. 'uw2', 'us-west-2', OR 'prod', 'staging', 'dev', 'UAT'" +} + +variable "stage" { + type = string + default = null + description = "Stage, e.g. 'prod', 'staging', 'dev', OR 'source', 'build', 'test', 'deploy', 'release'" +} + +variable "name" { + type = string + default = null + description = "Solution name, e.g. 'app' or 'jenkins'" +} + +variable "delimiter" { + type = string + default = null + description = <<-EOT + Delimiter to be used between `namespace`, `environment`, `stage`, `name` and `attributes`. + Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. + EOT +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)" +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. `map('BusinessUnit','XYZ')`" +} + +variable "additional_tag_map" { + type = map(string) + default = {} + description = "Additional tags for appending to tags_as_list_of_maps. Not added to `tags`." +} + +variable "label_order" { + type = list(string) + default = null + description = <<-EOT + The naming order of the id output and Name tag. + Defaults to ["namespace", "environment", "stage", "name", "attributes"]. + You can omit any of the 5 elements, but at least one must be present. + EOT +} + +variable "regex_replace_chars" { + type = string + default = null + description = <<-EOT + Regex to replace chars with empty string in `namespace`, `environment`, `stage` and `name`. + If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. + EOT +} + +variable "id_length_limit" { + type = number + default = null + description = <<-EOT + Limit `id` to this many characters (minimum 6). + Set to `0` for unlimited length. + Set to `null` for default, which is `0`. + Does not affect `id_full`. + EOT + validation { + condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 + error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." + } +} + +variable "label_key_case" { + type = string + default = null + description = <<-EOT + The letter case of label keys (`tag` names) (i.e. `name`, `namespace`, `environment`, `stage`, `attributes`) to use in `tags`. + Possible values: `lower`, `title`, `upper`. + Default value: `title`. + EOT + + validation { + condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) + error_message = "Allowed values: `lower`, `title`, `upper`." + } +} + +variable "label_value_case" { + type = string + default = null + description = <<-EOT + The letter case of output label values (also used in `tags` and `id`). + Possible values: `lower`, `title`, `upper` and `none` (no transformation). + Default value: `lower`. + EOT + + validation { + condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) + error_message = "Allowed values: `lower`, `title`, `upper`, `none`." + } +} +#### End of copy of cloudposse/terraform-null-label/variables.tf diff --git a/modules/integration_action/main.tf b/modules/integration_action/main.tf new file mode 100644 index 0000000..5d3fb93 --- /dev/null +++ b/modules/integration_action/main.tf @@ -0,0 +1,147 @@ +resource "opsgenie_integration_action" "this" { + count = module.this.enabled ? 1 : 0 + + integration_id = var.integration_action.integration_id + + dynamic "create" { + for_each = try(var.integration_action.create, []) + + content { + name = try(create.value.name, null) + order = try(create.value.order, null) + tags = try(create.value.tags, []) + user = try(create.value.user, null) + note = try(create.value.note, null) + alias = try(create.value.alias, null) + source = try(create.value.source, null) + message = try(create.value.message, null) + description = try(create.value.description, null) + entity = try(create.value.entity, null) + alert_actions = try(create.value.alert_actions, []) + extra_properties = try(create.value.extra_properties, {}) + custom_priority = try(create.value.custom_priority, null) + ignore_responders_from_payload = try(create.value.ignore_responders_from_payload, false) + ignore_teams_from_payload = try(create.value.ignore_teams_from_payload, false) + + responders { + id = var.integration_action.team_id + type = "team" + } + + filter { + type = try(create.value.filter.type, null) + + dynamic "conditions" { + for_each = try(create.value.filter.conditions, []) + + content { + field = try(conditions.value.field, null) + not = try(conditions.value.not, null) + operation = try(conditions.value.operation, null) + expected_value = try(conditions.value.expected_value, null) + } + } + } + } + } + + dynamic "close" { + for_each = try(var.integration_action.close, []) + + content { + name = try(close.value.name, null) + order = try(close.value.order, null) + alias = try(close.value.alias, null) + + filter { + type = try(close.value.filter.type, null) + + dynamic "conditions" { + for_each = try(close.value.filter.conditions, []) + + content { + field = try(conditions.value.field, null) + not = try(conditions.value.not, null) + operation = try(conditions.value.operation, null) + expected_value = try(conditions.value.expected_value, null) + } + } + } + } + } + + dynamic "acknowledge" { + for_each = try(var.integration_action.acknowledge, []) + + content { + name = try(acknowledge.value.name, null) + order = try(acknowledge.value.order, null) + alias = try(acknowledge.value.alias, null) + + filter { + type = try(acknowledge.value.filter.type, null) + + dynamic "conditions" { + for_each = try(acknowledge.value.filter.conditions, []) + + content { + field = try(conditions.value.field, null) + not = try(conditions.value.not, null) + operation = try(conditions.value.operation, null) + expected_value = try(conditions.value.expected_value, null) + } + } + } + } + } + + dynamic "add_note" { + for_each = try(var.integration_action.add_note, []) + + content { + name = try(add_note.value.name, null) + order = try(add_note.value.order, null) + alias = try(add_note.value.alias, null) + note = try(add_note.value.name, null) + + filter { + type = try(add_note.value.filter.type, null) + + dynamic "conditions" { + for_each = try(add_note.value.filter.conditions, []) + + content { + field = try(conditions.value.field, null) + not = try(conditions.value.not, null) + operation = try(conditions.value.operation, null) + expected_value = try(conditions.value.expected_value, null) + } + } + } + } + } + + dynamic "ignore" { + for_each = try(var.integration_action.ignore, []) + + content { + name = try(ignore.value.name, null) + order = try(ignore.value.order, null) + + filter { + type = try(ignore.value.filter.type, null) + + dynamic "conditions" { + for_each = try(ignore.value.filter.conditions, []) + + content { + field = try(conditions.value.field, null) + not = try(conditions.value.not, null) + operation = try(conditions.value.operation, null) + expected_value = try(conditions.value.expected_value, null) + } + } + } + } + } +} diff --git a/modules/integration_action/outputs.tf b/modules/integration_action/outputs.tf new file mode 100644 index 0000000..c510179 --- /dev/null +++ b/modules/integration_action/outputs.tf @@ -0,0 +1,4 @@ +output "integration_action_id" { + description = "The ID of the Opsgenie Integration Action" + value = try(opsgenie_integration_action.this[0].id, null) +} diff --git a/modules/integration_action/variables.tf b/modules/integration_action/variables.tf new file mode 100644 index 0000000..1eee418 --- /dev/null +++ b/modules/integration_action/variables.tf @@ -0,0 +1,4 @@ +variable "integration_action" { + default = {} + description = "Opsgenie Integration Action configuration" +} diff --git a/modules/integration_action/versions.tf b/modules/integration_action/versions.tf new file mode 100644 index 0000000..240bbd5 --- /dev/null +++ b/modules/integration_action/versions.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 0.13.0" + + required_providers { + opsgenie = { + source = "opsgenie/opsgenie" + version = ">= 0.4" + } + } +} diff --git a/outputs.tf b/outputs.tf index 876eeb2..dacecf8 100644 --- a/outputs.tf +++ b/outputs.tf @@ -54,6 +54,11 @@ output "escalation_name" { value = module.escalation.escalation_name } +output "integration_action_id" { + description = "The ID of the Opsgenie Integration Action" + value = module.integration_action.integration_action_id +} + output "notification_policy_id" { description = "The ID of the Opsgenie Notification Policy" value = module.notification_policy.notification_policy_id diff --git a/test/src/examples_advanced_features.go b/test/src/examples_advanced_features.go new file mode 100644 index 0000000..23267eb --- /dev/null +++ b/test/src/examples_advanced_features.go @@ -0,0 +1,24 @@ +package test + +import ( + "github.com/gruntwork-io/terratest/modules/terraform" + "testing" +) + + +// Test the Terraform module in examples/advanced_features using Terratest. +func TestExamplesAdvancedFeatures(t *testing.T) { + terraformOptions := &terraform.Options{ + // The path to where our Terraform code is located + TerraformDir: "../../examples/advanced_features", + Upgrade: true, + // Variables to pass to our Terraform code using -var-file options + VarFiles: []string{"fixtures.tfvars"}, + } + + // At the end of the test, run `terraform destroy` to clean up any resources that were created + defer terraform.Destroy(t, terraformOptions) + + // This will run `terraform init` and `terraform apply` and fail the test if there are any errors + terraform.InitAndApply(t, terraformOptions) +} diff --git a/test/src/examples_integration_action.go b/test/src/examples_integration_action.go new file mode 100644 index 0000000..2b88e89 --- /dev/null +++ b/test/src/examples_integration_action.go @@ -0,0 +1,24 @@ +package test + +import ( + "github.com/gruntwork-io/terratest/modules/terraform" + "testing" +) + + +// Test the Terraform module in examples/integration_action using Terratest. +func TestExamplesIntegrationAction(t *testing.T) { + terraformOptions := &terraform.Options{ + // The path to where our Terraform code is located + TerraformDir: "../../examples/integration_action", + Upgrade: true, + // Variables to pass to our Terraform code using -var-file options + VarFiles: []string{"fixtures.tfvars"}, + } + + // At the end of the test, run `terraform destroy` to clean up any resources that were created + defer terraform.Destroy(t, terraformOptions) + + // This will run `terraform init` and `terraform apply` and fail the test if there are any errors + terraform.InitAndApply(t, terraformOptions) +} diff --git a/variables.tf b/variables.tf index d818dde..9ad736a 100644 --- a/variables.tf +++ b/variables.tf @@ -19,6 +19,11 @@ variable "escalation" { description = "Opsgenie Escalation configuration" } +variable "integration_action" { + default = {} + description = "Opsgenie Integration Action configuration" +} + variable "notification_policy" { default = {} description = "Opsgenie Notification Policy configuration"