├── .editorconfig ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── bug_report.yml │ ├── config.yml │ ├── feature_request.md │ ├── feature_request.yml │ └── question.md ├── PULL_REQUEST_TEMPLATE.md ├── mergify.yml ├── renovate.json ├── settings.yml └── workflows │ ├── branch.yml │ ├── chatops.yml │ ├── release.yml │ └── scheduled.yml ├── .gitignore ├── LICENSE ├── README.md ├── README.yaml ├── atmos.yaml ├── context.tf ├── examples ├── advanced_features │ ├── api_integration.tf │ ├── context.tf │ ├── fixtures.tfvars │ ├── integration_action.tf │ ├── main.tf │ ├── outputs.tf │ ├── team.tf │ ├── variables.tf │ └── versions.tf ├── alert_policy │ ├── context.tf │ ├── fixtures.tfvars │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── api_integration │ ├── context.tf │ ├── fixtures.tfvars │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── complete │ ├── api_integration.tf │ ├── context.tf │ ├── escalation.tf │ ├── fixtures.tfvars │ ├── main.tf │ ├── outputs.tf │ ├── service.tf │ ├── service_incident_rule.tf │ ├── team.tf │ ├── team_routing_rule.tf │ ├── user.tf │ ├── variables.tf │ └── versions.tf ├── config │ ├── context.tf │ ├── fixtures.tfvars │ ├── main.tf │ ├── outputs.tf │ ├── resources │ │ ├── alert_policies.yaml │ │ ├── api_integrations.yaml │ │ ├── escalations.yaml │ │ ├── integration_actions.yaml │ │ ├── notification_policies.yaml │ │ ├── schedule_rotations.yaml │ │ ├── schedules.yaml │ │ ├── service_incident_rules.yaml │ │ ├── services.yaml │ │ ├── team_routing_rules.yaml │ │ ├── teams.yaml │ │ └── users.yaml │ ├── variables.tf │ └── versions.tf ├── escalation │ ├── context.tf │ ├── fixtures.tfvars │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── integration_action │ ├── context.tf │ ├── fixtures.tfvars │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── notification_policy │ ├── context.tf │ ├── fixtures.de_duplication_action.tfvars │ ├── fixtures.delay_action.tfvars │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── schedule │ ├── context.tf │ ├── fixtures.tfvars │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── team │ ├── context.tf │ ├── fixtures.tfvars │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── team_routing_rule │ ├── context.tf │ ├── fixtures.tfvars │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf └── user │ ├── context.tf │ ├── fixtures.tfvars │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── main.tf ├── modules ├── alert_policy │ ├── README.md │ ├── context.tf │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── api_integration │ ├── README.md │ ├── context.tf │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── config │ ├── README.md │ ├── alert_policies.tf │ ├── api_integrations.tf │ ├── context.tf │ ├── escalations.tf │ ├── existing_resources.tf │ ├── integration_actions.tf │ ├── main.tf │ ├── notification_policies.tf │ ├── outputs.tf │ ├── schedule_rotations.tf │ ├── schedules.tf │ ├── service_incident_rules.tf │ ├── services.tf │ ├── team_routing_rules.tf │ ├── teams.tf │ ├── users.tf │ ├── variables.tf │ └── versions.tf ├── escalation │ ├── README.md │ ├── context.tf │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── integration_action │ ├── README.md │ ├── context.tf │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── notification_policy │ ├── README.md │ ├── context.tf │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── schedule │ ├── README.md │ ├── context.tf │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── service │ ├── README.md │ ├── context.tf │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── service_incident_rule │ ├── README.md │ ├── context.tf │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── team │ ├── README.md │ ├── context.tf │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── team_routing_rule │ ├── README.md │ ├── context.tf │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf └── user │ ├── README.md │ ├── context.tf │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── outputs.tf ├── test ├── .gitignore ├── Makefile ├── Makefile.alpine └── src │ ├── .gitignore │ ├── Makefile │ ├── examples_advanced_features.go │ ├── examples_alert_policy_test.go │ ├── examples_api_integration_test.go │ ├── examples_complete_test.go │ ├── examples_config_test.go │ ├── examples_escalation_test.go │ ├── examples_integration_action.go │ ├── examples_notification_policy_test.go │ ├── examples_team_routing_rule_test.go │ ├── examples_team_test.go │ ├── examples_user_test.go │ ├── go.mod │ ├── go.sum │ └── utils.go ├── variables.tf └── versions.tf /.editorconfig: -------------------------------------------------------------------------------- 1 | # Unix-style newlines with a newline ending every file 2 | [*] 3 | charset = utf-8 4 | end_of_line = lf 5 | indent_size = 2 6 | indent_style = space 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | 10 | [*.{tf,tfvars}] 11 | indent_size = 2 12 | indent_style = space 13 | 14 | [*.md] 15 | max_line_length = 0 16 | trim_trailing_whitespace = false 17 | 18 | # Override for Makefile 19 | [{Makefile, makefile, GNUmakefile, Makefile.*}] 20 | tab_width = 2 21 | indent_style = tab 22 | indent_size = 4 23 | 24 | [COMMIT_EDITMSG] 25 | max_line_length = 0 26 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Use this file to define individuals or teams that are responsible for code in a repository. 2 | # Read more: 3 | # 4 | # Order is important: the last matching pattern has the highest precedence 5 | 6 | # These owners will be the default owners for everything 7 | * @cloudposse/engineering @cloudposse/contributors 8 | 9 | # Cloud Posse must review any changes to Makefiles 10 | **/Makefile @cloudposse/engineering 11 | **/Makefile.* @cloudposse/engineering 12 | 13 | # Cloud Posse must review any changes to GitHub actions 14 | .github/* @cloudposse/engineering 15 | 16 | # Cloud Posse must review any changes to standard context definition, 17 | # but some changes can be rubber-stamped. 18 | **/*.tf @cloudposse/engineering @cloudposse/contributors @cloudposse/approvers 19 | README.yaml @cloudposse/engineering @cloudposse/contributors @cloudposse/approvers 20 | README.md @cloudposse/engineering @cloudposse/contributors @cloudposse/approvers 21 | docs/*.md @cloudposse/engineering @cloudposse/contributors @cloudposse/approvers 22 | 23 | # Cloud Posse Admins must review all changes to CODEOWNERS or the mergify configuration 24 | .github/mergify.yml @cloudposse/admins 25 | .github/CODEOWNERS @cloudposse/admins 26 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: 'bug' 6 | assignees: '' 7 | 8 | --- 9 | 10 | Found a bug? Maybe our [Slack Community](https://slack.cloudposse.com) can help. 11 | 12 | [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) 13 | 14 | ## Describe the Bug 15 | A clear and concise description of what the bug is. 16 | 17 | ## Expected Behavior 18 | A clear and concise description of what you expected to happen. 19 | 20 | ## Steps to Reproduce 21 | Steps to reproduce the behavior: 22 | 1. Go to '...' 23 | 2. Run '....' 24 | 3. Enter '....' 25 | 4. See error 26 | 27 | ## Screenshots 28 | If applicable, add screenshots or logs to help explain your problem. 29 | 30 | ## Environment (please complete the following information): 31 | 32 | Anything that will help us triage the bug will help. Here are some ideas: 33 | - OS: [e.g. Linux, OSX, WSL, etc] 34 | - Version [e.g. 10.15] 35 | 36 | ## Additional Context 37 | Add any other context about the problem here. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | description: Create a report to help us improve 4 | labels: ["bug"] 5 | assignees: [""] 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | Found a bug? 11 | 12 | Please checkout our [Slack Community](https://slack.cloudposse.com) 13 | or visit our [Slack Archive](https://archive.sweetops.com/). 14 | 15 | [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) 16 | 17 | - type: textarea 18 | id: concise-description 19 | attributes: 20 | label: Describe the Bug 21 | description: A clear and concise description of what the bug is. 22 | placeholder: What is the bug about? 23 | validations: 24 | required: true 25 | 26 | - type: textarea 27 | id: expected 28 | attributes: 29 | label: Expected Behavior 30 | description: A clear and concise description of what you expected. 31 | placeholder: What happened? 32 | validations: 33 | required: true 34 | 35 | - type: textarea 36 | id: reproduction-steps 37 | attributes: 38 | label: Steps to Reproduce 39 | description: Steps to reproduce the behavior. 40 | placeholder: How do we reproduce it? 41 | validations: 42 | required: true 43 | 44 | - type: textarea 45 | id: screenshots 46 | attributes: 47 | label: Screenshots 48 | description: If applicable, add screenshots or logs to help explain. 49 | validations: 50 | required: false 51 | 52 | - type: textarea 53 | id: environment 54 | attributes: 55 | label: Environment 56 | description: Anything that will help us triage the bug. 57 | placeholder: | 58 | - OS: [e.g. Linux, OSX, WSL, etc] 59 | - Version [e.g. 10.15] 60 | - Module version 61 | - Terraform version 62 | validations: 63 | required: false 64 | 65 | - type: textarea 66 | id: additional 67 | attributes: 68 | label: Additional Context 69 | description: | 70 | Add any other context about the problem here. 71 | validations: 72 | required: false 73 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | 3 | contact_links: 4 | 5 | - name: Community Slack Team 6 | url: https://cloudposse.com/slack/ 7 | about: |- 8 | Please ask and answer questions here. 9 | 10 | - name: Office Hours 11 | url: https://cloudposse.com/office-hours/ 12 | about: |- 13 | Join us every Wednesday for FREE Office Hours (lunch & learn). 14 | 15 | - name: DevOps Accelerator Program 16 | url: https://cloudposse.com/accelerate/ 17 | about: |- 18 | Own your infrastructure in record time. We build it. You drive it. 19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature Request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: 'feature request' 6 | assignees: '' 7 | 8 | --- 9 | 10 | Have a question? Please checkout our [Slack Community](https://slack.cloudposse.com) or visit our [Slack Archive](https://archive.sweetops.com/). 11 | 12 | [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) 13 | 14 | ## Describe the Feature 15 | 16 | A clear and concise description of what the bug is. 17 | 18 | ## Expected Behavior 19 | 20 | A clear and concise description of what you expected to happen. 21 | 22 | ## Use Case 23 | 24 | Is your feature request related to a problem/challenge you are trying to solve? Please provide some additional context of why this feature or capability will be valuable. 25 | 26 | ## Describe Ideal Solution 27 | 28 | A clear and concise description of what you want to happen. If you don't know, that's okay. 29 | 30 | ## Alternatives Considered 31 | 32 | Explain what alternative solutions or features you've considered. 33 | 34 | ## Additional Context 35 | 36 | Add any other context or screenshots about the feature request here. 37 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature Request 3 | description: Suggest an idea for this project 4 | labels: ["feature request"] 5 | assignees: [""] 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: | 10 | Have a question? 11 | 12 | Please checkout our [Slack Community](https://slack.cloudposse.com) 13 | or visit our [Slack Archive](https://archive.sweetops.com/). 14 | 15 | [![Slack Community](https://slack.cloudposse.com/badge.svg)](https://slack.cloudposse.com) 16 | 17 | - type: textarea 18 | id: concise-description 19 | attributes: 20 | label: Describe the Feature 21 | description: A clear and concise description of what the feature is. 22 | placeholder: What is the feature about? 23 | validations: 24 | required: true 25 | 26 | - type: textarea 27 | id: expected 28 | attributes: 29 | label: Expected Behavior 30 | description: A clear and concise description of what you expected. 31 | placeholder: What happened? 32 | validations: 33 | required: true 34 | 35 | - type: textarea 36 | id: use-case 37 | attributes: 38 | label: Use Case 39 | description: | 40 | Is your feature request related to a problem/challenge you are trying 41 | to solve? 42 | 43 | Please provide some additional context of why this feature or 44 | capability will be valuable. 45 | validations: 46 | required: true 47 | 48 | - type: textarea 49 | id: ideal-solution 50 | attributes: 51 | label: Describe Ideal Solution 52 | description: A clear and concise description of what you want to happen. 53 | validations: 54 | required: true 55 | 56 | - type: textarea 57 | id: alternatives-considered 58 | attributes: 59 | label: Alternatives Considered 60 | description: Explain alternative solutions or features considered. 61 | validations: 62 | required: false 63 | 64 | - type: textarea 65 | id: additional 66 | attributes: 67 | label: Additional Context 68 | description: | 69 | Add any other context about the problem here. 70 | validations: 71 | required: false 72 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudposse/terraform-opsgenie-incident-management/cd773cad75c13a8391d3a7a46363add1d2db2902/.github/ISSUE_TEMPLATE/question.md -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## what 2 | 3 | 7 | 8 | ## why 9 | 10 | 15 | 16 | ## references 17 | 18 | 22 | -------------------------------------------------------------------------------- /.github/mergify.yml: -------------------------------------------------------------------------------- 1 | extends: .github 2 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base", 4 | ":preserveSemverRanges" 5 | ], 6 | "baseBranches": ["main", "master", "/^release\\/v\\d{1,2}$/"], 7 | "labels": ["auto-update"], 8 | "dependencyDashboardAutoclose": true, 9 | "enabledManagers": ["terraform"], 10 | "terraform": { 11 | "ignorePaths": ["**/context.tf", "examples/**"] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.github/settings.yml: -------------------------------------------------------------------------------- 1 | # Upstream changes from _extends are only recognized when modifications are made to this file in the default branch. 2 | _extends: .github 3 | repository: 4 | name: terraform-opsgenie-incident-management 5 | description: Terraform module to provision Opsgenie resources from YAML configurations using the Opsgenie provider,, complete with automated tests 6 | homepage: https://cloudposse.com/accelerate 7 | topics: opsgenie-provider, terraform-modules, terratest, opsgenie, opsgenie-api, escalation, notifications, y, yaml, yaml-configuration 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.github/workflows/branch.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Branch 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | - release/** 8 | types: [opened, synchronize, reopened, labeled, unlabeled] 9 | push: 10 | branches: 11 | - main 12 | - release/v* 13 | paths-ignore: 14 | - '.github/**' 15 | - 'docs/**' 16 | - 'examples/**' 17 | - 'test/**' 18 | - 'README.md' 19 | 20 | permissions: {} 21 | 22 | jobs: 23 | terraform-module: 24 | uses: cloudposse/.github/.github/workflows/shared-terraform-module.yml@main 25 | secrets: inherit 26 | -------------------------------------------------------------------------------- /.github/workflows/chatops.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: chatops 3 | on: 4 | issue_comment: 5 | types: [created] 6 | 7 | permissions: 8 | pull-requests: write 9 | id-token: write 10 | contents: write 11 | statuses: write 12 | 13 | jobs: 14 | test: 15 | uses: cloudposse/.github/.github/workflows/shared-terraform-chatops.yml@main 16 | if: ${{ github.event.issue.pull_request && contains(github.event.comment.body, '/terratest') }} 17 | secrets: inherit 18 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: release 3 | on: 4 | release: 5 | types: 6 | - published 7 | 8 | permissions: 9 | id-token: write 10 | contents: write 11 | pull-requests: write 12 | 13 | jobs: 14 | terraform-module: 15 | uses: cloudposse/.github/.github/workflows/shared-release-branches.yml@main 16 | secrets: inherit 17 | -------------------------------------------------------------------------------- /.github/workflows/scheduled.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: scheduled 3 | on: 4 | workflow_dispatch: { } # Allows manually trigger this workflow 5 | schedule: 6 | - cron: "0 3 * * *" 7 | 8 | permissions: 9 | pull-requests: write 10 | id-token: write 11 | contents: write 12 | 13 | jobs: 14 | scheduled: 15 | uses: cloudposse/.github/.github/workflows/shared-terraform-scheduled.yml@main 16 | secrets: inherit 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Local .terraform directories 2 | **/.terraform/* 3 | 4 | # .tfstate files 5 | *.tfstate 6 | *.tfstate.* 7 | .terraform 8 | .terraform.tfstate.lock.info 9 | 10 | **/.idea 11 | **/*.iml 12 | 13 | # Cloud Posse Build Harness https://github.com/cloudposse/build-harness 14 | **/.build-harness 15 | **/build-harness 16 | 17 | # Crash log files 18 | crash.log 19 | test.log 20 | -------------------------------------------------------------------------------- /README.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # This is the canonical configuration for the `README.md` 3 | # Run `make readme` to rebuild the `README.md` 4 | # 5 | 6 | # Name of this project 7 | name: terraform-opsgenie-incident-management 8 | 9 | # Logo for this project 10 | #logo: docs/logo.png 11 | 12 | # License of this project 13 | license: "APACHE2" 14 | 15 | # Copyrights 16 | copyrights: 17 | - name: "Cloud Posse, LLC" 18 | url: "https://cloudposse.com" 19 | year: "2021" 20 | 21 | # Canonical GitHub repo 22 | github_repo: cloudposse/terraform-opsgenie-incident-management 23 | 24 | # Badges to display 25 | badges: 26 | - name: Latest Release 27 | image: https://img.shields.io/github/release/cloudposse/terraform-opsgenie-incident-management.svg?style=for-the-badge 28 | url: https://github.com/cloudposse/terraform-opsgenie-incident-management/releases/latest 29 | - name: Last Updated 30 | image: https://img.shields.io/github/last-commit/cloudposse/terraform-opsgenie-incident-management.svg?style=for-the-badge 31 | url: https://github.com/cloudposse/terraform-opsgenie-incident-management/commits 32 | - name: Slack Community 33 | image: https://slack.cloudposse.com/for-the-badge.svg 34 | url: https://cloudposse.com/slack 35 | 36 | # List any related terraform modules that this module may be used with or that this module depends on. 37 | related: 38 | - name: "terraform-datadog-monitor" 39 | description: "Terraform module to provision Standard System Monitors (cpu, memory, swap, io, etc) in Datadog" 40 | url: "https://github.com/cloudposse/terraform-datadog-monitor" 41 | 42 | # List any resources helpful for someone to get started. For example, link to the hashicorp documentation or AWS documentation. 43 | references: 44 | - name: "Opsgenie API Overview" 45 | description: "Opsgenie APIs give you interconnectivity to process your requests and access data. View our individual documentation for our APIs to see the methods used to process relevant requests. Action-specific instructions are included to help you complete requests, along with sample requests and responses for added guidance. Additionally, view our Rate Limiting section for specific details and configurations." 46 | url: "https://docs.opsgenie.com/docs/api-overview" 47 | - name: "Terraform Registry Opsgenie Provider documentation" 48 | description: "The Opsgenie provider is used to interact with the many resources supported by Opsgenie. The provider needs to be configured with the proper credentials before it can be used." 49 | url: "https://registry.terraform.io/providers/opsgenie/opsgenie/latest/docs" 50 | - name: "Github Terraform OpsGenie provider repository" 51 | description: "The Opsgenie provider is used to interact with the many resources supported by Opsgenie. The provider needs to be configured with the proper credentials before it can be used." 52 | url: "https://github.com/opsgenie/terraform-provider-opsgenie/" 53 | 54 | # Short description of this project 55 | description: |- 56 | Terraform module to provision Opsgenie resources using the Opsgenie provider. The provider needs to be configured with the proper credentials before it can be used. 57 | It consist of root module which is only here as an example but can be used as a combination of all submodules. Submodules can also be combined to abstract away complexity of setting up for example a team escalation. 58 | 59 | # Introduction to the project 60 | introduction: |- 61 | Available modules: 62 | - [Alert Policy](modules/alert_policy) 63 | - [API Integration](modules/api_integration) 64 | - [Config](modules/config) 65 | - [Escalation](modules/escalation) 66 | - [Integration Action](modules/integration_action) (advanced feature — not available to all OpsGenie plans) 67 | - [Notification Policy](modules/notification_policy) 68 | - [Team](modules/team) 69 | - [Team Routing Rule](modules/team_routing_rule) 70 | - [User](modules/user) 71 | - [Service](modules/service) 72 | - [Service Incident Rule](modules/service_incident_rule) 73 | 74 | **Note:** Root module is just an example that uses all of submodules. 75 | 76 | **Note:** See the [Advanced Features Example](examples/advanced_features) for features only available to some OpsGenie plans. 77 | 78 | usage: |- 79 | Here's how to invoke `team` module in your projects 80 | 81 | ```hcl 82 | module "team-name" { 83 | source = "cloudposse/incident-management/opsgenie//modules/team" 84 | # Cloud Posse recommends pinning every module to a specific version 85 | # version = "x.x.x" 86 | 87 | team = { 88 | name = "team-name" 89 | description = "team-description" 90 | } 91 | } 92 | ``` 93 | 94 | # Example usage 95 | examples: |- 96 | Here are examples of using the module: 97 | 98 | - [`complete`](examples/complete) - complete example of using this module 99 | 100 | Submodules examples: 101 | - [`alert_policy`](examples/alert_policy) 102 | - [`api_integration`](examples/api_integration) 103 | - [`escalation`](examples/escalation) 104 | - [`integration_action`](examples/integration_action) (advanced feature — not available to all OpsGenie plans) 105 | - [`notification_policy`](examples/notification_policy) 106 | - [`team`](examples/team) 107 | - [`team_routing_rule`](examples/team_routing_rule) 108 | - [`user`](examples/user) 109 | 110 | Here is an example of using the `config` module, which incorporates all resource declarations into a single module: 111 | - [`config`](examples/config) 112 | 113 | Here are automated tests for the examples using [bats](https://github.com/bats-core/bats-core) and [Terratest](https://github.com/gruntwork-io/terratest) (which tests and provisions the examples): 114 | - [test](test) 115 | 116 | # How to get started quickly 117 | #quickstart: |- 118 | # Here's how to get started... 119 | 120 | # Other files to include in this README from the project folder 121 | include: [] 122 | contributors: [] 123 | -------------------------------------------------------------------------------- /atmos.yaml: -------------------------------------------------------------------------------- 1 | # Atmos Configuration — powered by https://atmos.tools 2 | # 3 | # This configuration enables centralized, DRY, and consistent project scaffolding using Atmos. 4 | # 5 | # Included features: 6 | # - Organizational custom commands: https://atmos.tools/core-concepts/custom-commands 7 | # - Automated README generation: https://atmos.tools/cli/commands/docs/generate 8 | # 9 | 10 | # Import shared configuration used by all modules 11 | import: 12 | - https://raw.githubusercontent.com/cloudposse/.github/refs/heads/main/.github/atmos/terraform-module.yaml 13 | -------------------------------------------------------------------------------- /context.tf: -------------------------------------------------------------------------------- 1 | # 2 | # ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label 3 | # All other instances of this file should be a copy of that one 4 | # 5 | # 6 | # Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf 7 | # and then place it in your Terraform module to automatically get 8 | # Cloud Posse's standard configuration inputs suitable for passing 9 | # to Cloud Posse modules. 10 | # 11 | # curl -sL https://raw.githubusercontent.com/cloudposse/terraform-null-label/master/exports/context.tf -o context.tf 12 | # 13 | # Modules should access the whole context as `module.this.context` 14 | # to get the input variables with nulls for defaults, 15 | # for example `context = module.this.context`, 16 | # and access individual variables as `module.this.`, 17 | # with final values filled in. 18 | # 19 | # For example, when using defaults, `module.this.context.delimiter` 20 | # will be null, and `module.this.delimiter` will be `-` (hyphen). 21 | # 22 | 23 | module "this" { 24 | source = "cloudposse/label/null" 25 | version = "0.25.0" # requires Terraform >= 0.13.0 26 | 27 | enabled = var.enabled 28 | namespace = var.namespace 29 | tenant = var.tenant 30 | environment = var.environment 31 | stage = var.stage 32 | name = var.name 33 | delimiter = var.delimiter 34 | attributes = var.attributes 35 | tags = var.tags 36 | additional_tag_map = var.additional_tag_map 37 | label_order = var.label_order 38 | regex_replace_chars = var.regex_replace_chars 39 | id_length_limit = var.id_length_limit 40 | label_key_case = var.label_key_case 41 | label_value_case = var.label_value_case 42 | descriptor_formats = var.descriptor_formats 43 | labels_as_tags = var.labels_as_tags 44 | 45 | context = var.context 46 | } 47 | 48 | # Copy contents of cloudposse/terraform-null-label/variables.tf here 49 | 50 | variable "context" { 51 | type = any 52 | default = { 53 | enabled = true 54 | namespace = null 55 | tenant = null 56 | environment = null 57 | stage = null 58 | name = null 59 | delimiter = null 60 | attributes = [] 61 | tags = {} 62 | additional_tag_map = {} 63 | regex_replace_chars = null 64 | label_order = [] 65 | id_length_limit = null 66 | label_key_case = null 67 | label_value_case = null 68 | descriptor_formats = {} 69 | # Note: we have to use [] instead of null for unset lists due to 70 | # https://github.com/hashicorp/terraform/issues/28137 71 | # which was not fixed until Terraform 1.0.0, 72 | # but we want the default to be all the labels in `label_order` 73 | # and we want users to be able to prevent all tag generation 74 | # by setting `labels_as_tags` to `[]`, so we need 75 | # a different sentinel to indicate "default" 76 | labels_as_tags = ["unset"] 77 | } 78 | description = <<-EOT 79 | Single object for setting entire context at once. 80 | See description of individual variables for details. 81 | Leave string and numeric variables as `null` to use default value. 82 | Individual variable settings (non-null) override settings in context object, 83 | except for attributes, tags, and additional_tag_map, which are merged. 84 | EOT 85 | 86 | validation { 87 | condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"]) 88 | error_message = "Allowed values: `lower`, `title`, `upper`." 89 | } 90 | 91 | validation { 92 | condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"]) 93 | error_message = "Allowed values: `lower`, `title`, `upper`, `none`." 94 | } 95 | } 96 | 97 | variable "enabled" { 98 | type = bool 99 | default = null 100 | description = "Set to false to prevent the module from creating any resources" 101 | } 102 | 103 | variable "namespace" { 104 | type = string 105 | default = null 106 | description = "ID element. Usually an abbreviation of your organization name, e.g. 'eg' or 'cp', to help ensure generated IDs are globally unique" 107 | } 108 | 109 | variable "tenant" { 110 | type = string 111 | default = null 112 | description = "ID element _(Rarely used, not included by default)_. A customer identifier, indicating who this instance of a resource is for" 113 | } 114 | 115 | variable "environment" { 116 | type = string 117 | default = null 118 | description = "ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT'" 119 | } 120 | 121 | variable "stage" { 122 | type = string 123 | default = null 124 | description = "ID element. Usually used to indicate role, e.g. 'prod', 'staging', 'source', 'build', 'test', 'deploy', 'release'" 125 | } 126 | 127 | variable "name" { 128 | type = string 129 | default = null 130 | description = <<-EOT 131 | ID element. Usually the component or solution name, e.g. 'app' or 'jenkins'. 132 | This is the only ID element not also included as a `tag`. 133 | The "name" tag is set to the full `id` string. There is no tag with the value of the `name` input. 134 | EOT 135 | } 136 | 137 | variable "delimiter" { 138 | type = string 139 | default = null 140 | description = <<-EOT 141 | Delimiter to be used between ID elements. 142 | Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. 143 | EOT 144 | } 145 | 146 | variable "attributes" { 147 | type = list(string) 148 | default = [] 149 | description = <<-EOT 150 | ID element. Additional attributes (e.g. `workers` or `cluster`) to add to `id`, 151 | in the order they appear in the list. New attributes are appended to the 152 | end of the list. The elements of the list are joined by the `delimiter` 153 | and treated as a single ID element. 154 | EOT 155 | } 156 | 157 | variable "labels_as_tags" { 158 | type = set(string) 159 | default = ["default"] 160 | description = <<-EOT 161 | Set of labels (ID elements) to include as tags in the `tags` output. 162 | Default is to include all labels. 163 | Tags with empty values will not be included in the `tags` output. 164 | Set to `[]` to suppress all generated tags. 165 | **Notes:** 166 | The value of the `name` tag, if included, will be the `id`, not the `name`. 167 | Unlike other `null-label` inputs, the initial setting of `labels_as_tags` cannot be 168 | changed in later chained modules. Attempts to change it will be silently ignored. 169 | EOT 170 | } 171 | 172 | variable "tags" { 173 | type = map(string) 174 | default = {} 175 | description = <<-EOT 176 | Additional tags (e.g. `{'BusinessUnit': 'XYZ'}`). 177 | Neither the tag keys nor the tag values will be modified by this module. 178 | EOT 179 | } 180 | 181 | variable "additional_tag_map" { 182 | type = map(string) 183 | default = {} 184 | description = <<-EOT 185 | Additional key-value pairs to add to each map in `tags_as_list_of_maps`. Not added to `tags` or `id`. 186 | This is for some rare cases where resources want additional configuration of tags 187 | and therefore take a list of maps with tag key, value, and additional configuration. 188 | EOT 189 | } 190 | 191 | variable "label_order" { 192 | type = list(string) 193 | default = null 194 | description = <<-EOT 195 | The order in which the labels (ID elements) appear in the `id`. 196 | Defaults to ["namespace", "environment", "stage", "name", "attributes"]. 197 | You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present. 198 | EOT 199 | } 200 | 201 | variable "regex_replace_chars" { 202 | type = string 203 | default = null 204 | description = <<-EOT 205 | Terraform regular expression (regex) string. 206 | Characters matching the regex will be removed from the ID elements. 207 | If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. 208 | EOT 209 | } 210 | 211 | variable "id_length_limit" { 212 | type = number 213 | default = null 214 | description = <<-EOT 215 | Limit `id` to this many characters (minimum 6). 216 | Set to `0` for unlimited length. 217 | Set to `null` for keep the existing setting, which defaults to `0`. 218 | Does not affect `id_full`. 219 | EOT 220 | validation { 221 | condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0 222 | error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length." 223 | } 224 | } 225 | 226 | variable "label_key_case" { 227 | type = string 228 | default = null 229 | description = <<-EOT 230 | Controls the letter case of the `tags` keys (label names) for tags generated by this module. 231 | Does not affect keys of tags passed in via the `tags` input. 232 | Possible values: `lower`, `title`, `upper`. 233 | Default value: `title`. 234 | EOT 235 | 236 | validation { 237 | condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case) 238 | error_message = "Allowed values: `lower`, `title`, `upper`." 239 | } 240 | } 241 | 242 | variable "label_value_case" { 243 | type = string 244 | default = null 245 | description = <<-EOT 246 | Controls the letter case of ID elements (labels) as included in `id`, 247 | set as tag values, and output by this module individually. 248 | Does not affect values of tags passed in via the `tags` input. 249 | Possible values: `lower`, `title`, `upper` and `none` (no transformation). 250 | Set this to `title` and set `delimiter` to `""` to yield Pascal Case IDs. 251 | Default value: `lower`. 252 | EOT 253 | 254 | validation { 255 | condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case) 256 | error_message = "Allowed values: `lower`, `title`, `upper`, `none`." 257 | } 258 | } 259 | 260 | variable "descriptor_formats" { 261 | type = any 262 | default = {} 263 | description = <<-EOT 264 | Describe additional descriptors to be output in the `descriptors` output map. 265 | Map of maps. Keys are names of descriptors. Values are maps of the form 266 | `{ 267 | format = string 268 | labels = list(string) 269 | }` 270 | (Type is `any` so the map values can later be enhanced to provide additional options.) 271 | `format` is a Terraform format string to be passed to the `format()` function. 272 | `labels` is a list of labels, in order, to pass to `format()` function. 273 | Label values will be normalized before being passed to `format()` so they will be 274 | identical to how they appear in `id`. 275 | Default is `{}` (`descriptors` output will be empty). 276 | EOT 277 | } 278 | 279 | #### End of copy of cloudposse/terraform-null-label/variables.tf 280 | -------------------------------------------------------------------------------- /examples/advanced_features/api_integration.tf: -------------------------------------------------------------------------------- 1 | module "api_integration" { 2 | source = "../../modules/api_integration" 3 | 4 | api_integration = { 5 | name = module.this.id 6 | type = "AmazonSns" 7 | owner_team_id = module.team.team_id 8 | } 9 | 10 | context = module.this.context 11 | } 12 | -------------------------------------------------------------------------------- /examples/advanced_features/fixtures.tfvars: -------------------------------------------------------------------------------- 1 | namespace = "eg" 2 | name = "incident-management-workflow" 3 | stage = "test" 4 | -------------------------------------------------------------------------------- /examples/advanced_features/integration_action.tf: -------------------------------------------------------------------------------- 1 | module "integration_action" { 2 | source = "../../modules/integration_action" 3 | 4 | integration_action = { 5 | integration_id = module.api_integration.api_integration_id 6 | team_id = module.team.team_id 7 | 8 | create = [ 9 | { 10 | name = "Create Non-informational Alerts" 11 | alias = "{{title}}" 12 | filter = { 13 | type = "match-all-conditions" 14 | conditions = [ 15 | { 16 | field = "priority" 17 | not = true 18 | operation = "equals" 19 | expected_value = "P5" 20 | } 21 | ] 22 | } 23 | } 24 | ] 25 | } 26 | 27 | context = module.this.context 28 | } 29 | -------------------------------------------------------------------------------- /examples/advanced_features/main.tf: -------------------------------------------------------------------------------- 1 | provider "opsgenie" { 2 | api_key = var.opsgenie_provider_api_key 3 | } 4 | -------------------------------------------------------------------------------- /examples/advanced_features/outputs.tf: -------------------------------------------------------------------------------- 1 | output "integration_action_id" { 2 | description = "The ID of the Opsgenie Integration Action" 3 | value = module.integration_action.integration_action_id 4 | } 5 | 6 | output "api_integration_id" { 7 | description = "The ID of the Opsgenie integration" 8 | value = module.api_integration.api_integration_id 9 | } 10 | 11 | output "api_integration_name" { 12 | description = "The name of the Opsgenie integration" 13 | value = module.api_integration.api_integration_name 14 | } 15 | 16 | output "team_id" { 17 | description = "The ID of the Opsgenie team" 18 | value = module.team.team_id 19 | } 20 | 21 | output "team_name" { 22 | description = "The name of the Opsgenie team" 23 | value = module.team.team_name 24 | } 25 | -------------------------------------------------------------------------------- /examples/advanced_features/team.tf: -------------------------------------------------------------------------------- 1 | module "team" { 2 | source = "../../modules/team" 3 | 4 | team = { 5 | name = "${module.this.id}.security" 6 | description = "${module.this.id} Security Team" 7 | ignore_members = false 8 | } 9 | 10 | context = module.this.context 11 | } 12 | -------------------------------------------------------------------------------- /examples/advanced_features/variables.tf: -------------------------------------------------------------------------------- 1 | variable "opsgenie_provider_api_key" { 2 | type = string 3 | description = "The API Key for the Opsgenie Integration. If omitted, the OPSGENIE_API_KEY environment variable is used" 4 | default = null 5 | } 6 | -------------------------------------------------------------------------------- /examples/advanced_features/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13.0" 3 | 4 | required_providers { 5 | opsgenie = { 6 | source = "opsgenie/opsgenie" 7 | version = ">= 0.4" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/alert_policy/fixtures.tfvars: -------------------------------------------------------------------------------- 1 | namespace = "eg" 2 | name = "alert-policy" 3 | stage = "test" 4 | -------------------------------------------------------------------------------- /examples/alert_policy/main.tf: -------------------------------------------------------------------------------- 1 | provider "opsgenie" { 2 | api_key = var.opsgenie_provider_api_key 3 | } 4 | 5 | module "alert_policy" { 6 | source = "../../modules/alert_policy" 7 | 8 | alert_policy = { 9 | name = module.this.id 10 | 11 | tags = ["test1", "test2"] 12 | priority = "P1" 13 | 14 | responders = [ 15 | { 16 | id = module.team.team_id 17 | type = "team" 18 | } 19 | ] 20 | 21 | filter = { 22 | type = "match-all-conditions" 23 | conditions = [ 24 | { 25 | # Possible values are "message", "alias", "description", "source", "entity", "tags", "actions", "details", "extra-properties", "recipients", "teams", "priority" 26 | field = "source" 27 | operation = "matches" 28 | expected_value = ".*prod.*" 29 | }, 30 | { 31 | field = "tags" 32 | operation = "contains" 33 | expected_value = "severity:critical" 34 | } 35 | ] 36 | } 37 | } 38 | 39 | context = module.this.context 40 | } 41 | 42 | module "team" { 43 | source = "../../modules/team" 44 | 45 | team = { 46 | name = module.this.id 47 | description = "team-description" 48 | } 49 | 50 | context = module.this.context 51 | } 52 | -------------------------------------------------------------------------------- /examples/alert_policy/outputs.tf: -------------------------------------------------------------------------------- 1 | output "alert_policy" { 2 | description = "Opsgenie Alert Policy" 3 | value = module.alert_policy 4 | } 5 | 6 | output "alert_policy_name" { 7 | description = "Name of the Opsgenie Alert Policy" 8 | value = module.alert_policy.alert_policy_name 9 | } 10 | 11 | output "alert_policy_tags" { 12 | description = "Tags of the Opsgenie Alert Policy" 13 | value = module.alert_policy.alert_policy_tags 14 | } 15 | 16 | output "alert_policy_filter" { 17 | description = "Filter of the Opsgenie Alert Policy" 18 | value = module.alert_policy.alert_policy_filter 19 | } 20 | 21 | output "alert_policy_priority" { 22 | description = "Priority of the Opsgenie Alert Policy" 23 | value = module.alert_policy.alert_policy_priority 24 | } 25 | 26 | output "alert_policy_responders" { 27 | description = "Responders of the Opsgenie Alert Policy" 28 | value = module.alert_policy.alert_policy_responders 29 | } 30 | -------------------------------------------------------------------------------- /examples/alert_policy/variables.tf: -------------------------------------------------------------------------------- 1 | variable "opsgenie_provider_api_key" { 2 | type = string 3 | description = "The API Key for the Opsgenie Integration. If omitted, the OPSGENIE_API_KEY environment variable is used" 4 | default = null 5 | } 6 | -------------------------------------------------------------------------------- /examples/alert_policy/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13.0" 3 | 4 | required_providers { 5 | opsgenie = { 6 | source = "opsgenie/opsgenie" 7 | version = ">= 0.4" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/api_integration/fixtures.tfvars: -------------------------------------------------------------------------------- 1 | namespace = "eg" 2 | name = "api-integration" 3 | stage = "test" 4 | -------------------------------------------------------------------------------- /examples/api_integration/main.tf: -------------------------------------------------------------------------------- 1 | provider "opsgenie" { 2 | api_key = var.opsgenie_provider_api_key 3 | } 4 | 5 | module "team" { 6 | source = "../../modules/team" 7 | 8 | team = { 9 | name = module.this.id 10 | } 11 | 12 | context = module.this.context 13 | } 14 | 15 | module "api_integration" { 16 | source = "../../modules/api_integration" 17 | 18 | api_integration = { 19 | name = module.this.id 20 | type = "AmazonSns" 21 | owner_team_id = module.team.team_id 22 | } 23 | 24 | context = module.this.context 25 | } 26 | -------------------------------------------------------------------------------- /examples/api_integration/outputs.tf: -------------------------------------------------------------------------------- 1 | output "api_integration_name" { 2 | description = "The name of the Opsgenie API Integration" 3 | value = module.api_integration.api_integration_name 4 | } 5 | 6 | output "api_integration_id" { 7 | description = "The ID of the Opsgenie API Integration" 8 | value = module.api_integration.api_integration_id 9 | } 10 | 11 | output "api_integration_api_key" { 12 | description = "The API key of the Opsgenie API Integration" 13 | value = module.api_integration.api_integration_api_key 14 | sensitive = true 15 | } 16 | -------------------------------------------------------------------------------- /examples/api_integration/variables.tf: -------------------------------------------------------------------------------- 1 | variable "opsgenie_provider_api_key" { 2 | type = string 3 | description = "The API Key for the Opsgenie Integration. If omitted, the OPSGENIE_API_KEY environment variable is used" 4 | default = null 5 | } 6 | -------------------------------------------------------------------------------- /examples/api_integration/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13.0" 3 | 4 | required_providers { 5 | opsgenie = { 6 | source = "opsgenie/opsgenie" 7 | version = ">= 0.4" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/complete/api_integration.tf: -------------------------------------------------------------------------------- 1 | module "api_integration" { 2 | source = "../../modules/api_integration" 3 | 4 | api_integration = { 5 | name = module.this.id 6 | type = "AmazonSns" 7 | owner_team_id = module.team.team_id 8 | } 9 | context = module.this.context 10 | } 11 | -------------------------------------------------------------------------------- /examples/complete/escalation.tf: -------------------------------------------------------------------------------- 1 | module "escalation" { 2 | source = "../../modules/escalation" 3 | 4 | escalation = { 5 | name = "${module.this.id}-escalation" 6 | owner_team_id = module.team.team_id 7 | 8 | rules = [{ 9 | recipient = { 10 | type = "team" 11 | id = module.sub_team.team_id 12 | } 13 | }] 14 | } 15 | 16 | context = module.this.context 17 | } 18 | -------------------------------------------------------------------------------- /examples/complete/fixtures.tfvars: -------------------------------------------------------------------------------- 1 | namespace = "eg" 2 | name = "incident-management-workflow" 3 | stage = "test" 4 | -------------------------------------------------------------------------------- /examples/complete/main.tf: -------------------------------------------------------------------------------- 1 | provider "opsgenie" { 2 | api_key = var.opsgenie_provider_api_key 3 | } 4 | -------------------------------------------------------------------------------- /examples/complete/outputs.tf: -------------------------------------------------------------------------------- 1 | output "escalation_id" { 2 | description = "The ID of the Opsgenie escalation" 3 | value = module.escalation.escalation_id 4 | } 5 | 6 | output "escalation_name" { 7 | description = "The name of the Opsgenie escalation" 8 | value = module.escalation.escalation_name 9 | } 10 | 11 | output "api_integration_id" { 12 | description = "The ID of the Opsgenie integration" 13 | value = module.api_integration.api_integration_id 14 | } 15 | 16 | output "api_integration_name" { 17 | description = "The name of the Opsgenie integration" 18 | value = module.api_integration.api_integration_name 19 | } 20 | 21 | output "team_routing_rule_id" { 22 | description = "The ID of the Opsgenie team routing rule" 23 | value = module.team_routing_rule.team_routing_rule_id 24 | } 25 | 26 | output "team_routing_rule_name" { 27 | description = "The name of the Opsgenie team routing rule" 28 | value = module.team_routing_rule.team_routing_rule_name 29 | } 30 | 31 | output "team_id" { 32 | description = "The ID of the Opsgenie team" 33 | value = module.team.team_id 34 | } 35 | 36 | output "team_name" { 37 | description = "The name of the Opsgenie team" 38 | value = module.team.team_name 39 | } 40 | 41 | output "user_id" { 42 | description = "The ID of the Opsgenie user" 43 | value = module.user.user_id 44 | } 45 | 46 | output "user_name" { 47 | description = "The name of the Opsgenie user" 48 | value = module.user.user_name 49 | } 50 | 51 | output "service_id" { 52 | description = "The ID of the Opsgenie service" 53 | value = module.service.service_id 54 | } 55 | 56 | output "service_name" { 57 | description = "The name of the Opsgenie service" 58 | value = module.service.service_name 59 | } 60 | 61 | output "service_incident_rule_id" { 62 | description = "The ID of the Opsgenie service incident rule" 63 | value = module.service_incident_rule.service_incident_rule_id 64 | } 65 | -------------------------------------------------------------------------------- /examples/complete/service.tf: -------------------------------------------------------------------------------- 1 | module "service" { 2 | source = "../../modules/service" 3 | 4 | # Services are Opsgenie Enterprise feature, disable it for now 5 | enabled = false 6 | 7 | service = { 8 | name = "frontend" 9 | description = "Frontend service" 10 | team_id = module.team.team_id 11 | } 12 | 13 | context = module.this.context 14 | } 15 | -------------------------------------------------------------------------------- /examples/complete/service_incident_rule.tf: -------------------------------------------------------------------------------- 1 | module "service_incident_rule" { 2 | source = "../../modules/service_incident_rule" 3 | 4 | # Services are Opsgenie Enterprise feature, disable it for now 5 | enabled = false 6 | 7 | service_incident_rule = { 8 | service_id = module.service.service_id 9 | 10 | incident_rule = { 11 | condition_match_type = "match-all" 12 | 13 | conditions = [ 14 | { 15 | # Possibke values: message, description, tags, extra-properties, recipients, teams, priority 16 | field = "message" 17 | operation = "matches" 18 | expected_value = ".*stage.*" 19 | }, 20 | { 21 | field = "tags" 22 | operation = "contains" 23 | expected_value = "severity:info" 24 | } 25 | ] 26 | 27 | incident_properties = { 28 | message = "This is a test message" 29 | priority = "P3" 30 | 31 | stakeholder_properties = { 32 | message = "Message for stakeholders" 33 | enable = true 34 | } 35 | } 36 | } 37 | } 38 | 39 | context = module.this.context 40 | } 41 | -------------------------------------------------------------------------------- /examples/complete/team.tf: -------------------------------------------------------------------------------- 1 | module "team" { 2 | source = "../../modules/team" 3 | 4 | team = { 5 | name = module.this.id 6 | description = "team-description" 7 | ignore_members = false 8 | } 9 | context = module.this.context 10 | } 11 | 12 | module "sub_team" { 13 | source = "../../modules/team" 14 | 15 | team = { 16 | name = "${module.this.id}.team" 17 | description = "sub-team-description" 18 | } 19 | context = module.this.context 20 | } 21 | -------------------------------------------------------------------------------- /examples/complete/team_routing_rule.tf: -------------------------------------------------------------------------------- 1 | module "team_routing_rule" { 2 | source = "../../modules/team_routing_rule" 3 | 4 | team_routing_rule = { 5 | name = module.this.id 6 | team_id = module.team.team_id 7 | 8 | notify = [{ 9 | type = "escalation" 10 | id = module.escalation.escalation_id 11 | }] 12 | } 13 | 14 | context = module.this.context 15 | } 16 | -------------------------------------------------------------------------------- /examples/complete/user.tf: -------------------------------------------------------------------------------- 1 | module "user" { 2 | source = "../../modules/user" 3 | 4 | # Users can't be destroyed 5 | enabled = false 6 | 7 | user = { 8 | username = "opsgenie-test@cloudposse.com" 9 | full_name = "Opsgenie Test User" 10 | role = "User" 11 | locale = "en_US" 12 | timezone = "America/New_York" 13 | } 14 | 15 | context = module.this.context 16 | } 17 | -------------------------------------------------------------------------------- /examples/complete/variables.tf: -------------------------------------------------------------------------------- 1 | variable "opsgenie_provider_api_key" { 2 | type = string 3 | description = "The API Key for the Opsgenie Integration. If omitted, the OPSGENIE_API_KEY environment variable is used" 4 | default = null 5 | } 6 | -------------------------------------------------------------------------------- /examples/complete/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13.0" 3 | 4 | required_providers { 5 | opsgenie = { 6 | source = "opsgenie/opsgenie" 7 | version = ">= 0.4" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/config/fixtures.tfvars: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudposse/terraform-opsgenie-incident-management/cd773cad75c13a8391d3a7a46363add1d2db2902/examples/config/fixtures.tfvars -------------------------------------------------------------------------------- /examples/config/main.tf: -------------------------------------------------------------------------------- 1 | provider "opsgenie" { 2 | api_key = var.opsgenie_provider_api_key 3 | } 4 | 5 | locals { 6 | # Build a map of our various Opsgenie resources that will be used to iterate over each module 7 | opsgenie_resources = merge([ 8 | for resource_file in fileset(path.cwd, "resources/*.yaml") : { 9 | for k, v in yamldecode(file(resource_file)) : k => v 10 | } 11 | ]...) 12 | } 13 | 14 | module "opsgenie_config" { 15 | source = "../../modules/config" 16 | 17 | opsgenie_resources = local.opsgenie_resources 18 | 19 | context = module.this.context 20 | } 21 | -------------------------------------------------------------------------------- /examples/config/outputs.tf: -------------------------------------------------------------------------------- 1 | output "api_integrations" { 2 | value = module.opsgenie_config.api_integrations 3 | description = "API integrations" 4 | } 5 | 6 | output "alert_policies" { 7 | value = module.opsgenie_config.alert_policies 8 | description = "Alert policies" 9 | } 10 | 11 | output "escalations" { 12 | value = module.opsgenie_config.escalations 13 | description = "Escalations" 14 | } 15 | 16 | output "integration_actions" { 17 | value = module.opsgenie_config.integration_actions 18 | description = "Integration Actions" 19 | } 20 | 21 | output "notification_policies" { 22 | value = module.opsgenie_config.notification_policies 23 | description = "Notification policies" 24 | } 25 | 26 | output "team_routing_rules" { 27 | value = module.opsgenie_config.team_routing_rules 28 | description = "Team routing rules" 29 | } 30 | 31 | output "teams" { 32 | value = module.opsgenie_config.teams 33 | description = "Teams" 34 | } 35 | 36 | output "users" { 37 | value = module.opsgenie_config.users 38 | description = "Users" 39 | } 40 | 41 | output "services" { 42 | value = module.opsgenie_config.services 43 | description = "Services" 44 | } 45 | 46 | output "service_incident_rule_ids" { 47 | value = module.opsgenie_config.service_incident_rule_ids 48 | description = "Service Incident Rule IDs" 49 | } 50 | -------------------------------------------------------------------------------- /examples/config/resources/alert_policies.yaml: -------------------------------------------------------------------------------- 1 | alert_policies: 2 | - name: "prioritize-env-prod-critical-alerts" 3 | owner_team_name: acme.dev 4 | tags: 5 | - "ManagedBy:terraform" 6 | filter: 7 | type: match-all-conditions 8 | conditions: 9 | - field: source 10 | operation: matches 11 | expected_value: ".*prod.acme.*" 12 | - field: tags 13 | operation: contains 14 | expected_value: "severity:critical" 15 | priority: P1 16 | -------------------------------------------------------------------------------- /examples/config/resources/api_integrations.yaml: -------------------------------------------------------------------------------- 1 | api_integrations: 2 | - name: acme-dev-opsgenie-sns-integration 3 | type: AmazonSns 4 | owner_team_name: acme.dev 5 | -------------------------------------------------------------------------------- /examples/config/resources/escalations.yaml: -------------------------------------------------------------------------------- 1 | escalations: 2 | - name: acme.dev.some-service-escalation 3 | description: "repo: https://github.com/acme/some-service;owner:David Lightman @David Lightman" 4 | owner_team_name: acme.dev 5 | rules: 6 | - condition: if-not-acked 7 | notify_type: default 8 | delay: 0 9 | recipient: 10 | type: team 11 | team_name: acme.dev.some-service 12 | -------------------------------------------------------------------------------- /examples/config/resources/integration_actions.yaml: -------------------------------------------------------------------------------- 1 | integration_actions: 2 | - name: acme-dev-opsgenie-sns-close-low-priority 3 | integration_name: acme-dev-opsgenie-sns-integration 4 | create: 5 | - name: Create Non-informational Alerts 6 | alias: "{{title}}" 7 | filter: 8 | type: match-all-conditions 9 | conditions: 10 | - field: priority 11 | not: true 12 | operation: equals 13 | expected_value: P5 14 | -------------------------------------------------------------------------------- /examples/config/resources/notification_policies.yaml: -------------------------------------------------------------------------------- 1 | notification_policies: 2 | - name: auto-close-based-on-priority 3 | team_name: acme.dev 4 | auto_close_action: 5 | duration: 6 | time_amount: 60 7 | filter: 8 | type: match-all-conditions 9 | conditions: 10 | - field: priority 11 | operation: less-than 12 | expected_value: P3 13 | de_duplication_action: 14 | de_duplication_action_type: frequency-based 15 | count: 2 16 | duration: 17 | time_unit: minutes 18 | time_amount: 5 19 | 20 | - name: delay-action-test 21 | team_name: acme.dev 22 | auto_close_action: 23 | duration: 24 | time_amount: 60 25 | filter: 26 | type: match-all-conditions 27 | conditions: 28 | - field: priority 29 | operation: less-than 30 | expected_value: P3 31 | delay_action: 32 | delay_option: for-duration 33 | duration: 34 | time_unit: minutes 35 | time_amount: 5 36 | -------------------------------------------------------------------------------- /examples/config/resources/schedule_rotations.yaml: -------------------------------------------------------------------------------- 1 | schedule_rotations: 2 | - name: acme.default.rotation 3 | schedule_name: acme-default 4 | start_date: "1970-01-01T00:00:00Z" 5 | type: weekly 6 | length: 1 7 | participants: 8 | - type: user 9 | username: opsgenie-test@cloudposse.com 10 | - type: user 11 | username: opsgenie-test-2@cloudposse.com 12 | - type: none 13 | time_restriction: 14 | type: time-of-day 15 | restrictions: 16 | - start_hour: 8 17 | start_min: 0 18 | end_hour: 20 19 | end_min: 0 20 | -------------------------------------------------------------------------------- /examples/config/resources/schedules.yaml: -------------------------------------------------------------------------------- 1 | schedules: 2 | - name: acme-default 3 | description: "Acme Infrastructure Team" 4 | timezone: "America/Los_Angeles" 5 | owner_team_name: acme 6 | enabled: true 7 | -------------------------------------------------------------------------------- /examples/config/resources/service_incident_rules.yaml: -------------------------------------------------------------------------------- 1 | service_incident_rules: 2 | - name: frontend-service-incident-rule-1 3 | service_name: frontend 4 | 5 | incident_rule: 6 | condition_match_type: match-all 7 | 8 | conditions: 9 | - field: message 10 | operation: matches 11 | expected_value: ".*stage.*" 12 | - field: tags 13 | operation: contains 14 | expected_value: "severity:info" 15 | 16 | incident_properties: 17 | message: This is a test message 18 | priority: P3 19 | 20 | stakeholder_properties: 21 | message: Message for stakeholders 22 | enable: true 23 | -------------------------------------------------------------------------------- /examples/config/resources/services.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | - name: frontend 3 | description: Frontend service 4 | team_name: acme 5 | -------------------------------------------------------------------------------- /examples/config/resources/team_routing_rules.yaml: -------------------------------------------------------------------------------- 1 | team_routing_rules: 2 | - name: some-service 3 | owner_team_name: acme.dev 4 | criteria: 5 | type: match-all-conditions 6 | conditions: 7 | - field: tags 8 | operation: contains 9 | expected_value: app:some-service 10 | not: false 11 | notify: 12 | - type: escalation 13 | name: acme.dev.some-service-escalation 14 | order: 0 15 | -------------------------------------------------------------------------------- /examples/config/resources/teams.yaml: -------------------------------------------------------------------------------- 1 | teams: 2 | - name: acme 3 | description: Global Team for Acme Co. 4 | members: 5 | username: opsgenie-test@cloudposse.com 6 | role: admin 7 | - name: acme.dev 8 | description: Acme Dev Team 9 | delete_default_resources: true 10 | members: 11 | username: opsgenie-test@cloudposse.com 12 | role: admin 13 | - name: acme.dev.some-service 14 | description: "repo: https://github.com/acme/some-service;owner:David Lightman @David Lightman" 15 | ignore_members: true 16 | delete_default_resources: true 17 | members: 18 | username: opsgenie-test@cloudposse.com 19 | role: admin 20 | -------------------------------------------------------------------------------- /examples/config/resources/users.yaml: -------------------------------------------------------------------------------- 1 | users: 2 | - username: opsgenie-test@cloudposse.com 3 | full_name: Opsgenie Test User 4 | role: User 5 | locale: "en_US" 6 | timezone: "America/New_York" 7 | 8 | - username: opsgenie-test-2@cloudposse.com 9 | full_name: Opsgenie Test User 2 10 | role: User 11 | locale: "en_US" 12 | timezone: "America/New_York" 13 | -------------------------------------------------------------------------------- /examples/config/variables.tf: -------------------------------------------------------------------------------- 1 | variable "opsgenie_provider_api_key" { 2 | type = string 3 | description = "The API Key for the Opsgenie Integration. If omitted, the OPSGENIE_API_KEY environment variable is used" 4 | default = null 5 | } 6 | -------------------------------------------------------------------------------- /examples/config/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13.0" 3 | 4 | required_providers { 5 | opsgenie = { 6 | source = "opsgenie/opsgenie" 7 | version = ">= 0.4" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/escalation/fixtures.tfvars: -------------------------------------------------------------------------------- 1 | namespace = "eg" 2 | name = "escalation" 3 | stage = "test" 4 | -------------------------------------------------------------------------------- /examples/escalation/main.tf: -------------------------------------------------------------------------------- 1 | provider "opsgenie" { 2 | api_key = var.opsgenie_provider_api_key 3 | } 4 | 5 | module "owner_team" { 6 | source = "../../modules/team" 7 | 8 | team = { 9 | name = format("%s-%s", module.this.id, "owner-team") 10 | description = "owner-team-description" 11 | } 12 | 13 | context = module.this.context 14 | } 15 | 16 | module "escalation_team" { 17 | source = "../../modules/team" 18 | 19 | team = { 20 | name = format("%s-%s", module.this.id, "escalation-team") 21 | description = "owner-team-description" 22 | } 23 | 24 | context = module.this.context 25 | } 26 | 27 | module "escalation" { 28 | source = "../../modules/escalation" 29 | 30 | escalation = { 31 | name = module.this.id 32 | owner_team_id = module.owner_team.team_id 33 | 34 | rules = [{ 35 | delay = 0 36 | recipient = { 37 | type = "team" 38 | id = module.escalation_team.team_id 39 | } 40 | }] 41 | } 42 | 43 | context = module.this.context 44 | } 45 | -------------------------------------------------------------------------------- /examples/escalation/outputs.tf: -------------------------------------------------------------------------------- 1 | output "escalation" { 2 | description = "Opsgenie Escalation" 3 | value = module.escalation 4 | } 5 | 6 | output "escalation_name" { 7 | description = "The Name of the Opsgenie Escalation" 8 | value = module.escalation.escalation_name 9 | } 10 | 11 | output "escalation_id" { 12 | description = "The ID of the Opsgenie Escalation" 13 | value = module.escalation.escalation_id 14 | } 15 | -------------------------------------------------------------------------------- /examples/escalation/variables.tf: -------------------------------------------------------------------------------- 1 | variable "opsgenie_provider_api_key" { 2 | type = string 3 | description = "The API Key for the Opsgenie Integration. If omitted, the OPSGENIE_API_KEY environment variable is used" 4 | default = null 5 | } 6 | -------------------------------------------------------------------------------- /examples/escalation/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13.0" 3 | 4 | required_providers { 5 | opsgenie = { 6 | source = "opsgenie/opsgenie" 7 | version = ">= 0.4" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/integration_action/fixtures.tfvars: -------------------------------------------------------------------------------- 1 | namespace = "eg" 2 | name = "integration" 3 | stage = "test" 4 | -------------------------------------------------------------------------------- /examples/integration_action/main.tf: -------------------------------------------------------------------------------- 1 | provider "opsgenie" { 2 | api_key = var.opsgenie_provider_api_key 3 | } 4 | 5 | module "team" { 6 | source = "../../modules/team" 7 | 8 | team = { 9 | name = module.this.id 10 | } 11 | 12 | context = module.this.context 13 | } 14 | 15 | module "api_integration" { 16 | source = "../../modules/api_integration" 17 | 18 | api_integration = { 19 | name = module.this.id 20 | type = "AmazonSns" 21 | owner_team_id = module.team.team_id 22 | } 23 | 24 | context = module.this.context 25 | } 26 | 27 | module "integration_action" { 28 | source = "../../modules/integration_action" 29 | 30 | integration_action = { 31 | integration_id = module.api_integration.api_integration_id 32 | team_id = module.team.team_id 33 | 34 | create = [ 35 | { 36 | name = "Create Non-informational Alerts" 37 | alias = "{{title}}" 38 | filter = { 39 | type = "match-all-conditions" 40 | conditions = [ 41 | { 42 | field = "priority" 43 | not = true 44 | operation = "equals" 45 | expected_value = "P5" 46 | } 47 | ] 48 | } 49 | } 50 | ] 51 | } 52 | 53 | context = module.this.context 54 | } 55 | -------------------------------------------------------------------------------- /examples/integration_action/outputs.tf: -------------------------------------------------------------------------------- 1 | output "integration_action" { 2 | description = "Opsgenie Integration Action" 3 | value = module.integration_action 4 | } 5 | 6 | output "integration_action_id" { 7 | description = "The ID of the Opsgenie Integration Action" 8 | value = module.integration_action.integration_action_id 9 | } 10 | -------------------------------------------------------------------------------- /examples/integration_action/variables.tf: -------------------------------------------------------------------------------- 1 | variable "opsgenie_provider_api_key" { 2 | type = string 3 | description = "The API Key for the Opsgenie Integration. If omitted, the OPSGENIE_API_KEY environment variable is used" 4 | default = null 5 | } 6 | -------------------------------------------------------------------------------- /examples/integration_action/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13.0" 3 | 4 | required_providers { 5 | opsgenie = { 6 | source = "opsgenie/opsgenie" 7 | version = ">= 0.4" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/notification_policy/fixtures.de_duplication_action.tfvars: -------------------------------------------------------------------------------- 1 | namespace = "eg" 2 | name = "notification-policy" 3 | stage = "test" 4 | 5 | de_duplication_action = { 6 | de_duplication_action_type = "frequency-based" 7 | count = 2 8 | duration = { 9 | time_unit = "minutes" 10 | time_amount = 5 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/notification_policy/fixtures.delay_action.tfvars: -------------------------------------------------------------------------------- 1 | namespace = "eg" 2 | name = "notification-policy" 3 | stage = "test" 4 | 5 | delay_action = { 6 | delay_option = "for-duration" 7 | duration = { 8 | time_unit = "minutes" 9 | time_amount = 10 10 | } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /examples/notification_policy/main.tf: -------------------------------------------------------------------------------- 1 | provider "opsgenie" { 2 | api_key = var.opsgenie_provider_api_key 3 | } 4 | 5 | module "team" { 6 | source = "../../modules/team" 7 | 8 | team = { 9 | name = module.this.id 10 | description = "owner-team-description" 11 | } 12 | 13 | context = module.this.context 14 | } 15 | 16 | module "notification_policy" { 17 | source = "../../modules/notification_policy" 18 | 19 | notification_policy = { 20 | name = module.this.id 21 | team_id = module.team.team_id 22 | 23 | filter = { 24 | type = "match-all-conditions" 25 | conditions = [ 26 | { 27 | field = "tags" 28 | operation = "contains" 29 | expected_value = "recommendation:auto-close" 30 | } 31 | ] 32 | } 33 | 34 | de_duplication_action = var.de_duplication_action 35 | delay_action = var.delay_action 36 | 37 | auto_close_action = { 38 | duration = { 39 | time_unit = "minutes" 40 | time_amount = 5 41 | } 42 | } 43 | 44 | auto_restart_action = { 45 | duration = { 46 | time_unit = "minutes" 47 | time_amount = 5 48 | } 49 | max_repeat_count = 3 50 | } 51 | 52 | suppress = var.suppress 53 | } 54 | 55 | context = module.this.context 56 | } 57 | -------------------------------------------------------------------------------- /examples/notification_policy/outputs.tf: -------------------------------------------------------------------------------- 1 | output "notification_policy" { 2 | description = "Opsgenie Notification Policy" 3 | value = module.notification_policy 4 | } 5 | 6 | output "notification_policy_id" { 7 | description = "The ID of the Opsgenie Notification Policy" 8 | value = module.notification_policy.notification_policy_id 9 | } 10 | 11 | output "notification_policy_name" { 12 | description = "The name of the Opsgenie Notification Policy" 13 | value = module.notification_policy.notification_policy_name 14 | } 15 | -------------------------------------------------------------------------------- /examples/notification_policy/variables.tf: -------------------------------------------------------------------------------- 1 | variable "opsgenie_provider_api_key" { 2 | type = string 3 | description = "The API Key for the Opsgenie Integration. If omitted, the OPSGENIE_API_KEY environment variable is used" 4 | default = null 5 | } 6 | 7 | variable "de_duplication_action" { 8 | type = object({ 9 | de_duplication_action_type = string 10 | count = number 11 | duration = object({ 12 | time_unit = string 13 | time_amount = number 14 | }) 15 | }) 16 | description = "The de-duplication action for the notification policy" 17 | default = null 18 | } 19 | 20 | variable "delay_action" { 21 | type = object({ 22 | delay_option = string 23 | duration = object({ 24 | time_unit = string 25 | time_amount = number 26 | }) 27 | }) 28 | description = "The delay action for the notification policy" 29 | default = null 30 | } 31 | 32 | variable "suppress" { 33 | type = bool 34 | description = "The suppress flag for the notification policy" 35 | default = null 36 | } 37 | -------------------------------------------------------------------------------- /examples/notification_policy/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13.0" 3 | 4 | required_providers { 5 | opsgenie = { 6 | source = "opsgenie/opsgenie" 7 | version = ">= 0.4" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/schedule/fixtures.tfvars: -------------------------------------------------------------------------------- 1 | namespace = "eg" 2 | name = "schedule" 3 | stage = "test" 4 | -------------------------------------------------------------------------------- /examples/schedule/main.tf: -------------------------------------------------------------------------------- 1 | provider "opsgenie" { 2 | api_key = var.opsgenie_provider_api_key 3 | } 4 | 5 | module "owner_team" { 6 | source = "../../modules/team" 7 | 8 | team = { 9 | name = format("%s-%s", module.this.id, "owner-team") 10 | description = "owner-team-description" 11 | } 12 | 13 | context = module.this.context 14 | } 15 | 16 | module "team_schedule" { 17 | source = "../../modules/schedule" 18 | 19 | schedule = { 20 | enabled = module.this.enabled 21 | name = module.this.id 22 | description = "team-schedule-description" 23 | owner_team_id = module.owner_team.team_id 24 | } 25 | 26 | context = module.this.context 27 | } 28 | 29 | module "schedule" { 30 | source = "../../modules/schedule" 31 | 32 | schedule = { 33 | enabled = module.this.enabled 34 | name = module.this.id 35 | description = "schedule-description" 36 | } 37 | 38 | context = module.this.context 39 | } 40 | -------------------------------------------------------------------------------- /examples/schedule/outputs.tf: -------------------------------------------------------------------------------- 1 | output "team" { 2 | description = "Opsgenie Team" 3 | value = module.team 4 | } 5 | 6 | output "team_id" { 7 | description = "The ID of the Opsgenie Team" 8 | value = module.team.team_id 9 | } 10 | 11 | output "team_name" { 12 | description = "The name of the Opsgenie Team" 13 | value = module.team.team_name 14 | } 15 | -------------------------------------------------------------------------------- /examples/schedule/variables.tf: -------------------------------------------------------------------------------- 1 | variable "opsgenie_provider_api_key" { 2 | type = string 3 | description = "The API Key for the Opsgenie Integration. If omitted, the OPSGENIE_API_KEY environment variable is used" 4 | default = null 5 | } 6 | -------------------------------------------------------------------------------- /examples/schedule/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13.0" 3 | 4 | required_providers { 5 | opsgenie = { 6 | source = "opsgenie/opsgenie" 7 | version = ">= 0.6.7" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/team/fixtures.tfvars: -------------------------------------------------------------------------------- 1 | namespace = "eg" 2 | name = "team" 3 | stage = "test" 4 | -------------------------------------------------------------------------------- /examples/team/main.tf: -------------------------------------------------------------------------------- 1 | provider "opsgenie" { 2 | api_key = var.opsgenie_provider_api_key 3 | } 4 | 5 | module "team" { 6 | source = "../../modules/team" 7 | 8 | team = { 9 | name = module.this.id 10 | description = "team-description" 11 | } 12 | 13 | context = module.this.context 14 | } 15 | -------------------------------------------------------------------------------- /examples/team/outputs.tf: -------------------------------------------------------------------------------- 1 | output "team" { 2 | description = "Opsgenie Team" 3 | value = module.team 4 | } 5 | 6 | output "team_id" { 7 | description = "The ID of the Opsgenie Team" 8 | value = module.team.team_id 9 | } 10 | 11 | output "team_name" { 12 | description = "The name of the Opsgenie Team" 13 | value = module.team.team_name 14 | } 15 | -------------------------------------------------------------------------------- /examples/team/variables.tf: -------------------------------------------------------------------------------- 1 | variable "opsgenie_provider_api_key" { 2 | type = string 3 | description = "The API Key for the Opsgenie Integration. If omitted, the OPSGENIE_API_KEY environment variable is used" 4 | default = null 5 | } 6 | -------------------------------------------------------------------------------- /examples/team/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13.0" 3 | 4 | required_providers { 5 | opsgenie = { 6 | source = "opsgenie/opsgenie" 7 | version = ">= 0.4" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/team_routing_rule/fixtures.tfvars: -------------------------------------------------------------------------------- 1 | namespace = "eg" 2 | name = "team-routing-rule" 3 | stage = "test" 4 | -------------------------------------------------------------------------------- /examples/team_routing_rule/main.tf: -------------------------------------------------------------------------------- 1 | provider "opsgenie" { 2 | api_key = var.opsgenie_provider_api_key 3 | } 4 | 5 | module "escalation_team" { 6 | source = "../../modules/team" 7 | 8 | team = { 9 | name = module.this.id 10 | description = "escalation-team-description" 11 | } 12 | 13 | context = module.this.context 14 | } 15 | 16 | module "escalation" { 17 | source = "../../modules/escalation" 18 | 19 | escalation = { 20 | name = module.this.id 21 | owner_team_id = module.owner_team.team_id 22 | 23 | rules = [{ 24 | recipient = { 25 | type = "team" 26 | id = module.escalation_team.team_id 27 | } 28 | }] 29 | } 30 | 31 | context = module.this.context 32 | } 33 | 34 | module "owner_team" { 35 | source = "../../modules/team" 36 | 37 | team = { 38 | name = format("%s-%s", module.this.id, "owner-team") 39 | description = "owner-team-description" 40 | } 41 | 42 | context = module.this.context 43 | } 44 | 45 | module "team_routing_rule" { 46 | source = "../../modules/team_routing_rule" 47 | 48 | team_routing_rule = { 49 | name = module.this.id 50 | team_id = module.owner_team.team_id 51 | 52 | notify = [ 53 | { 54 | type = "escalation" 55 | id = module.escalation.escalation_id 56 | } 57 | ] 58 | 59 | time_restriction = { 60 | type = "time-of-day" 61 | restrictions = [ 62 | { 63 | end_hour = 17 64 | end_min = 0 65 | start_hour = 9 66 | start_min = 0 67 | } 68 | ] 69 | } 70 | } 71 | 72 | context = module.this.context 73 | } 74 | -------------------------------------------------------------------------------- /examples/team_routing_rule/outputs.tf: -------------------------------------------------------------------------------- 1 | output "team_routing_rule" { 2 | description = "Opsgenie Team Routing Rule" 3 | value = module.team_routing_rule 4 | } 5 | 6 | output "team_routing_rule_id" { 7 | description = "The ID of the Opsgenie Team Routing Rule" 8 | value = module.team_routing_rule.team_routing_rule_id 9 | } 10 | 11 | output "team_routing_rule_name" { 12 | description = "The name of the Opsgenie Team Routing Rule" 13 | value = module.team_routing_rule.team_routing_rule_name 14 | } 15 | -------------------------------------------------------------------------------- /examples/team_routing_rule/variables.tf: -------------------------------------------------------------------------------- 1 | variable "opsgenie_provider_api_key" { 2 | type = string 3 | description = "The API Key for the Opsgenie Integration. If omitted, the OPSGENIE_API_KEY environment variable is used" 4 | default = null 5 | } 6 | -------------------------------------------------------------------------------- /examples/team_routing_rule/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13.0" 3 | 4 | required_providers { 5 | opsgenie = { 6 | source = "opsgenie/opsgenie" 7 | version = ">= 0.4" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/user/fixtures.tfvars: -------------------------------------------------------------------------------- 1 | namespace = "eg" 2 | stage = "test" 3 | name = "user" 4 | -------------------------------------------------------------------------------- /examples/user/main.tf: -------------------------------------------------------------------------------- 1 | provider "opsgenie" { 2 | api_key = var.opsgenie_provider_api_key 3 | } 4 | 5 | module "user" { 6 | source = "../../modules/user" 7 | 8 | user = { 9 | username = format("opsgenie-test+%s@cloudposse.com", var.random_string) 10 | full_name = "Opsgenie Test User" 11 | role = "User" 12 | locale = "en_US" 13 | timezone = "America/New_York" 14 | } 15 | 16 | context = module.this.context 17 | } 18 | -------------------------------------------------------------------------------- /examples/user/outputs.tf: -------------------------------------------------------------------------------- 1 | output "user" { 2 | description = "Opsgenie User" 3 | value = module.user 4 | } 5 | 6 | output "user_id" { 7 | description = "The ID of the Opsgenie User" 8 | value = module.user.user_id 9 | } 10 | 11 | output "user_name" { 12 | description = "The name of the Opsgenie User" 13 | value = module.user.user_name 14 | } 15 | -------------------------------------------------------------------------------- /examples/user/variables.tf: -------------------------------------------------------------------------------- 1 | variable "opsgenie_provider_api_key" { 2 | type = string 3 | description = "The API Key for the Opsgenie Integration. If omitted, the OPSGENIE_API_KEY environment variable is used" 4 | default = null 5 | } 6 | 7 | variable "random_string" { 8 | type = string 9 | description = "A random string to append to the resource names" 10 | default = null 11 | } 12 | -------------------------------------------------------------------------------- /examples/user/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13.0" 3 | 4 | required_providers { 5 | opsgenie = { 6 | source = "opsgenie/opsgenie" 7 | version = ">= 0.4" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /main.tf: -------------------------------------------------------------------------------- 1 | provider "opsgenie" { 2 | api_key = var.opsgenie_provider_api_key 3 | } 4 | 5 | module "alert_policy" { 6 | source = "./modules/alert_policy" 7 | 8 | alert_policy = var.alert_policy 9 | context = module.this.context 10 | } 11 | 12 | module "api_integration" { 13 | source = "./modules/api_integration" 14 | 15 | api_integration = var.api_integration 16 | context = module.this.context 17 | } 18 | 19 | module "escalation" { 20 | source = "./modules/escalation" 21 | 22 | escalation = var.escalation 23 | context = module.this.context 24 | } 25 | 26 | module "integration_action" { 27 | source = "./modules/integration_action" 28 | 29 | integration_action = var.integration_action 30 | context = module.this.context 31 | } 32 | 33 | module "notification_policy" { 34 | source = "./modules/notification_policy" 35 | 36 | notification_policy = var.notification_policy 37 | context = module.this.context 38 | } 39 | 40 | module "team" { 41 | source = "./modules/team" 42 | 43 | team = var.team 44 | context = module.this.context 45 | } 46 | 47 | module "team_routing_rule" { 48 | source = "./modules/team_routing_rule" 49 | 50 | team_routing_rule = var.team_routing_rule 51 | context = module.this.context 52 | } 53 | 54 | module "user" { 55 | source = "./modules/user" 56 | 57 | user = var.user 58 | context = module.this.context 59 | } 60 | 61 | module "service" { 62 | source = "./modules/service" 63 | 64 | service = var.service 65 | context = module.this.context 66 | } 67 | 68 | module "service_incident_rule" { 69 | source = "./modules/service_incident_rule" 70 | 71 | service_incident_rule = var.service_incident_rule 72 | context = module.this.context 73 | } 74 | -------------------------------------------------------------------------------- /modules/alert_policy/README.md: -------------------------------------------------------------------------------- 1 | ## Alert Policy 2 | 3 | Terraform module to configure [Opsgenie Alert Policy](https://registry.terraform.io/providers/opsgenie/opsgenie/latest/docs/resources/alert_policy) 4 | 5 | 6 | ## Usage 7 | 8 | [Create Opsgenie Alert Policy example](../../examples/alert_policy) 9 | 10 | ```hcl 11 | module "alert_policy" { 12 | source = "cloudposse/incident-management/opsgenie//modules/alert_policy" 13 | # Cloud Posse recommends pinning every module to a specific version 14 | # version = "x.x.x" 15 | 16 | alert_policy = { 17 | name = "alert-policy" 18 | 19 | tags = ["test1", "test2"] 20 | priority = "P1" 21 | 22 | filter = { 23 | type = "match-all-conditions" 24 | conditions = [ 25 | { 26 | field = "source" 27 | operation = "matches" 28 | expected_value = ".*prod.*" 29 | }, 30 | { 31 | field = "tags" 32 | operation = "contains" 33 | expected_value = "severity:critical" 34 | } 35 | ] 36 | } 37 | } 38 | } 39 | ``` 40 | 41 | ## Inputs 42 | 43 | **Note:** `alert_policy` is a map for two reasons: 44 | - to be able to put whole configuration in yaml file 45 | - variables defined with type set are not robust enough (can't set default values) 46 | 47 | | Name | Default | Description | Required | 48 | |:-------------------------------|:---------------------------------:|:--------------------------------------------------------------------------------------------------------------------------------|:--------:| 49 | | `alert_policy` | `{}` | This variable is used to configure Opsgenie Alert Policy. | Yes | 50 | 51 | 52 | ## Outputs 53 | 54 | | Name | Description | 55 | |:----------------------------|:----------------------------------------| 56 | | `alert_policy_id` | The ID of the Opsgenie Alert Policy. | 57 | | `alert_policy_name` | Name of the Opsgenie Alert Policy. | 58 | | `alert_policy_filter` | Filters of the Opsgenie Alert Policy. | 59 | | `alert_policy_tags` | Tags of the Opsgenie Alert Policy. | 60 | | `alert_policy_priority` | Priority of the Opsgenie Alert Policy. | 61 | | `alert_policy_responders` | Responders of the Opsgenie Alert Policy.| 62 | -------------------------------------------------------------------------------- /modules/alert_policy/main.tf: -------------------------------------------------------------------------------- 1 | resource "opsgenie_alert_policy" "this" { 2 | count = module.this.enabled ? 1 : 0 3 | 4 | name = var.alert_policy.name 5 | policy_description = try(var.alert_policy.description, var.alert_policy.name) 6 | team_id = try(var.alert_policy.team_id, null) 7 | 8 | enabled = try(var.alert_policy.enabled, true) 9 | continue_policy = try(var.alert_policy.continue, true) 10 | 11 | alias = try(var.alert_policy.alias, null) 12 | entity = try(var.alert_policy.entity, null) 13 | message = try(var.alert_policy.message, "{{ message }}") 14 | priority = try(var.alert_policy.priority, null) 15 | source = try(var.alert_policy.source, null) 16 | tags = try(var.alert_policy.tags, null) 17 | 18 | ignore_original_actions = try(var.alert_policy.ignore_original_actions, false) 19 | ignore_original_details = try(var.alert_policy.ignore_original_details, false) 20 | ignore_original_responders = try(var.alert_policy.ignore_original_responders, false) 21 | ignore_original_tags = try(var.alert_policy.ignore_original_tags, false) 22 | 23 | dynamic "responders" { 24 | for_each = try(var.alert_policy.responders, []) 25 | 26 | content { 27 | id = responders.value.id 28 | name = try(responders.value.name, null) 29 | type = responders.value.type 30 | username = try(responders.value.username, null) 31 | } 32 | } 33 | 34 | filter { 35 | type = try(var.alert_policy.filter.type, "match-all") 36 | 37 | dynamic "conditions" { 38 | for_each = try(var.alert_policy.filter.conditions, []) 39 | 40 | content { 41 | expected_value = try(conditions.value.expected_value, null) 42 | field = try(conditions.value.field, null) 43 | key = try(conditions.value.key, null) 44 | not = try(conditions.value.not, null) 45 | operation = try(conditions.value.operation, null) 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /modules/alert_policy/outputs.tf: -------------------------------------------------------------------------------- 1 | output "alert_policy_id" { 2 | description = "The ID of the Opsgenie Alert Policy" 3 | value = try(opsgenie_alert_policy.this[0].id, null) 4 | } 5 | 6 | output "alert_policy_name" { 7 | description = "Name of the Opsgenie Alert Policy" 8 | value = try(opsgenie_alert_policy.this[0].name, null) 9 | } 10 | 11 | output "alert_policy_filter" { 12 | description = "Filters of the Opsgenie Alert Policy" 13 | value = try(opsgenie_alert_policy.this[0].filter, null) 14 | } 15 | 16 | output "alert_policy_tags" { 17 | description = "Tags of the Opsgenie Alert Policy" 18 | value = try(opsgenie_alert_policy.this[0].tags, null) 19 | } 20 | 21 | output "alert_policy_priority" { 22 | description = "Priority of the Opsgenie Alert Policy" 23 | value = try(opsgenie_alert_policy.this[0].priority, null) 24 | } 25 | 26 | output "alert_policy_responders" { 27 | description = "Responders of the Opsgenie Alert Policy" 28 | value = try(opsgenie_alert_policy.this[0].responders, null) 29 | } 30 | -------------------------------------------------------------------------------- /modules/alert_policy/variables.tf: -------------------------------------------------------------------------------- 1 | variable "alert_policy" { 2 | default = {} 3 | description = "Opsgenie Alert Policy configuration" 4 | } 5 | -------------------------------------------------------------------------------- /modules/alert_policy/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13.0" 3 | 4 | required_providers { 5 | opsgenie = { 6 | source = "opsgenie/opsgenie" 7 | version = ">= 0.4" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/api_integration/README.md: -------------------------------------------------------------------------------- 1 | ## API Integration 2 | 3 | Terraform module to configure [Opsgenie API Integration](https://registry.terraform.io/providers/opsgenie/opsgenie/latest/docs/resources/api_integration) 4 | 5 | 6 | ## Usage 7 | 8 | [Create Opsgenie API Integration example](../../examples/alert_policy) 9 | 10 | ```hcl 11 | module "api_integration" { 12 | source = "cloudposse/incident-management/opsgenie//modules/api_integration" 13 | # Cloud Posse recommends pinning every module to a specific version 14 | # version = "x.x.x" 15 | 16 | api_integration = { 17 | name = module.label.id 18 | type = "AmazonSns" 19 | owner_team_id = module.team.team_id 20 | } 21 | } 22 | ``` 23 | 24 | ## Inputs 25 | 26 | **Note:** `api_integration` is a map for two reasons: 27 | - to be able to put whole configuration in yaml file 28 | - variables defined with type set are not robust enough (can't set default values) 29 | 30 | | Name | Default | Description | Required | 31 | |:-------------------------------|:---------------------------------:|:--------------------------------------------------------------------------------------------------------------------------------|:--------:| 32 | | `api_integration` | `{}` | This variable is used to configure Opsgenie API Integration. | Yes | 33 | 34 | 35 | ## Outputs 36 | 37 | | Name | Description | 38 | |:----------------------------|:-----------------------------------------| 39 | | `api_integration_api_key` | API key of the created integration | 40 | | `api_integration_name` | The name of the Opsgenie API Integration.| 41 | | `api_integration_id` | The ID of the Opsgenie API Integration. | 42 | -------------------------------------------------------------------------------- /modules/api_integration/main.tf: -------------------------------------------------------------------------------- 1 | resource "opsgenie_api_integration" "this" { 2 | count = module.this.enabled ? 1 : 0 3 | 4 | name = var.api_integration.name 5 | type = var.api_integration.type 6 | 7 | dynamic "responders" { 8 | for_each = try(var.api_integration.responders, []) 9 | 10 | content { 11 | type = responders.value.type 12 | id = responders.value.id 13 | } 14 | } 15 | 16 | enabled = try(var.api_integration.enabled, true) 17 | allow_write_access = try(var.api_integration.allow_write_access, true) 18 | ignore_responders_from_payload = try(var.api_integration.ignore_responders_from_payload, false) 19 | suppress_notifications = try(var.api_integration.suppress_notifications, false) 20 | webhook_url = try(var.api_integration.webhook_url, null) 21 | 22 | owner_team_id = try(var.api_integration.owner_team_id, null) 23 | } 24 | -------------------------------------------------------------------------------- /modules/api_integration/outputs.tf: -------------------------------------------------------------------------------- 1 | output "api_integration_api_key" { 2 | description = "API key of the created integration" 3 | value = try(opsgenie_api_integration.this[0].api_key, null) 4 | sensitive = true 5 | } 6 | 7 | output "api_integration_name" { 8 | description = "The name of the Opsgenie API Integration" 9 | value = try(opsgenie_api_integration.this[0].name, null) 10 | } 11 | 12 | output "api_integration_id" { 13 | description = "The ID of the Opsgenie API Integration" 14 | value = try(opsgenie_api_integration.this[0].id, null) 15 | } 16 | -------------------------------------------------------------------------------- /modules/api_integration/variables.tf: -------------------------------------------------------------------------------- 1 | variable "api_integration" { 2 | type = map(any) 3 | default = {} 4 | description = "Opsgenie API Integration configuration" 5 | } 6 | -------------------------------------------------------------------------------- /modules/api_integration/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13.0" 3 | 4 | required_providers { 5 | opsgenie = { 6 | source = "opsgenie/opsgenie" 7 | version = ">= 0.4" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/config/README.md: -------------------------------------------------------------------------------- 1 | ## Config 2 | 3 | Terraform module that configures a multitude of [Opsgenie resources](https://registry.terraform.io/providers/opsgenie/opsgenie/latest/docs). 4 | Many resources have cross-resource dependencies, which may be simpler to handle within a single module in certain cases, such as using YAML configurations. 5 | 6 | This module is designed to accept an input configuration map. 7 | One nice way of handling this is by passing resource definitions from a YAML configuration file. 8 | 9 | See below for details & examples. 10 | 11 | ## YAML Examples 12 | 13 | ### `alert_policies.yaml` 14 | 15 | ```yaml 16 | alert_policies: 17 | - name: "prioritize-env-prod-critical-alerts" 18 | owner_team_name: acme.dev 19 | tags: 20 | - "ManagedBy:terraform" 21 | filter: 22 | type: match-all-conditions 23 | conditions: 24 | - field: source 25 | operation: matches 26 | expected_value: ".*prod.acme.*" 27 | - field: tags 28 | operation: contains 29 | expected_value: "severity:critical" 30 | priority: P1 31 | ``` 32 | 33 | ### `api_integrations.yaml` 34 | 35 | ```yaml 36 | api_integrations: 37 | - name: acme-dev-opsgenie-sns-integration 38 | type: AmazonSns 39 | owner_team_name: acme.dev 40 | ``` 41 | 42 | ### `escalations.yaml` 43 | 44 | ```yaml 45 | escalations: 46 | - name: acme.dev.some-service-escalation 47 | description: "repo: https://github.com/acme/some-service;owner:David Lightman @David Lightman" 48 | owner_team_name: acme.dev 49 | rules: 50 | - condition: if-not-acked 51 | notify_type: default 52 | delay: 0 53 | recipient: 54 | type: team 55 | team_name: acme.dev.some-service 56 | ``` 57 | 58 | ### `notification_policies.yaml` 59 | 60 | ```yaml 61 | notification_policies: 62 | - name: auto-close-based-on-priority 63 | team_name: acme.dev 64 | auto_close_action: 65 | time_amount: 60 66 | filter: 67 | type: match-all-conditions 68 | conditions: 69 | - field: priority 70 | operation: less-than 71 | expected_value: P3 72 | ``` 73 | 74 | ### `schedules.yaml` 75 | 76 | ```yaml 77 | schedules: 78 | - name: acme.default 79 | description: "Acme Infrastructure Team" 80 | timezone: "America/Los_Angeles" 81 | owner_team_name: acme 82 | enabled: true 83 | ``` 84 | 85 | ### `schedule_rotations.yaml` 86 | 87 | ```yaml 88 | schedule_rotations: 89 | - name: acme.default.rotation 90 | schedule_name: acme.default 91 | start_date: "1970-01-01T00:00:00Z" 92 | type: weekly 93 | length: 1 94 | participants: 95 | - type: user 96 | username: opsgenie-test@cloudposse.com 97 | - type: none 98 | - type: user 99 | username: opsgenie-test-2@cloudposse.com 100 | time_restriction: 101 | type: time-of-day 102 | restrictions: 103 | - start_hour: 8 104 | start_min: 0 105 | end_hour: 20 106 | end_min: 0 107 | ``` 108 | 109 | ### `team_routing_rules.yaml` 110 | 111 | ```yaml 112 | team_routing_rules: 113 | - name: some-service 114 | owner_team_name: acme.dev 115 | criteria: 116 | type: match-all-conditions 117 | conditions: 118 | - field: tags 119 | operation: contains 120 | expected_value: app:some-service 121 | not: false 122 | notify: 123 | - type: escalation 124 | name: acme.dev.some-service-escalation 125 | order: 0 126 | ``` 127 | 128 | ### `teams.yaml` 129 | 130 | ```yaml 131 | teams: 132 | - name: acme 133 | description: Global Team for Acme Co. 134 | - name: acme.dev 135 | description: Acme Dev Team 136 | - name: acme.dev.some-service 137 | description: "repo: https://github.com/acme/some-service;owner:David Lightman @David Lightman" 138 | ``` 139 | 140 | ### `users.yaml` 141 | 142 | ```yaml 143 | users: 144 | - username: opsgenie-test@cloudposse.com 145 | full_name: Opsgenie Test User 146 | role: User 147 | locale: "en_US" 148 | timezone: "America/New_York" 149 | ``` 150 | 151 | 152 | ### `existing_schedules.yaml` 153 | 154 | ```yaml 155 | existing_schedules: 156 | - acme.default 157 | ``` 158 | 159 | 160 | ### `existing_teams.yaml` 161 | 162 | ```yaml 163 | existing_teams: 164 | - acme 165 | ``` 166 | 167 | 168 | ### `existing_users.yaml` 169 | 170 | ```yaml 171 | existing_users: 172 | - username: opsgenie-test@cloudposse.com 173 | ``` 174 | 175 | 176 | ### `services.yaml` 177 | 178 | ```yaml 179 | services: 180 | - name: frontend 181 | team_id: "..." 182 | description: Frontend service 183 | ``` 184 | 185 | ### `service_incident_rules.yaml` 186 | 187 | ```yaml 188 | service_incident_rules: 189 | - name: frontend-service-incident-rule-1 190 | service_name: frontend 191 | incident_rule: 192 | condition_match_type: match-all 193 | 194 | conditions: 195 | - field: source 196 | operation: matches 197 | expected_value: ".*stage.*" 198 | - field: tags 199 | operation: contains 200 | expected_value: "severity:info" 201 | 202 | incident_properties: 203 | message: This is a test message 204 | priority: P3 205 | 206 | stakeholder_properties: 207 | message: Message for stakeholders 208 | enable: true 209 | ``` 210 | 211 | ## Usage 212 | 213 | [Full Config Example](../../examples/config) 214 | 215 | ```hcl 216 | locals { 217 | # Build a map of our various Opsgenie resources that will be used to iterate over each module 218 | opsgenie_resources = merge([ 219 | for resource_file in fileset(path.cwd, "resources/*.yaml") : { 220 | for k, v in yamldecode(file(resource_file)) : k => v 221 | } 222 | ]...) 223 | } 224 | 225 | module "opsgenie" { 226 | source = "cloudposse/incident-management/opsgenie//modules/config" 227 | # Cloud Posse recommends pinning every module to a specific version 228 | # version = "x.x.x" 229 | 230 | opsgenie_resources = local.opsgenie_resources 231 | } 232 | ``` 233 | 234 | ## Inputs 235 | 236 | | Name | Default | Description | Required | 237 | |:-------------------------------|:----------------:|:-------------------------------------------------------------------------------|:--------:| 238 | | `opsgenie_resources` | `{}` | A map generated by sourcing YAML resource definitions (see above). | Yes | 239 | 240 | 241 | ## Outputs 242 | 243 | | Name | Description | 244 | |:----------------------------|:--------------------------------------------| 245 | | `alert_policies` | `name` and `id` of each alert policy | 246 | | `api_integrations` | `name` and `id` of each API integration | 247 | | `escalations` | `name` and `id` of each escalation | 248 | | `existing_schedules` | `name` and `id` of each existing schedule | 249 | | `existing_teams` | `name` and `id` of each existing team | 250 | | `existing_users` | `username` and `id` of each existing user | 251 | | `notification_policies` | `name` and `id` of each notification policy | 252 | | `schedules` | `name` and `id` of each schedules | 253 | | `schedule_rotations` | `name` and `id` of each schedule rotations | 254 | | `services` | `name` and `id` of each service | 255 | | `services` | `name` and `id` of each service | 256 | | `service_incident_rule_ids` | `id` of each service incident rule | 257 | | `team_routing_rules` | `name` and `id` of each team routing rule | 258 | | `teams` | `name` and `id` of each team | 259 | | `users` | `username` and `id` of each user | 260 | -------------------------------------------------------------------------------- /modules/config/alert_policies.tf: -------------------------------------------------------------------------------- 1 | # https://docs.opsgenie.com/docs/alert-api 2 | 3 | resource "opsgenie_alert_policy" "this" { 4 | for_each = module.this.enabled ? { for policy in local.alert_policies : policy.name => policy } : {} 5 | 6 | name = each.value.name 7 | policy_description = try(each.value.policy_description, each.value.name) 8 | alert_description = try(each.value.alert_description, each.value.name) 9 | 10 | # Look up our team id by name 11 | team_id = try(opsgenie_team.this[each.value.owner_team_name].id, data.opsgenie_team.this[each.value.owner_team_name].id, null) 12 | 13 | enabled = try(each.value.enabled, true) 14 | continue_policy = try(each.value.continue, true) 15 | 16 | alias = try(each.value.alias, null) 17 | entity = try(each.value.entity, null) 18 | message = try(each.value.message, "{{message}}") 19 | priority = try(each.value.priority, null) 20 | source = try(each.value.source, null) 21 | tags = try(each.value.tags, null) 22 | 23 | ignore_original_actions = try(each.value.ignore_original_actions, false) 24 | ignore_original_details = try(each.value.ignore_original_details, false) 25 | ignore_original_responders = try(each.value.ignore_original_responders, false) 26 | ignore_original_tags = try(each.value.ignore_original_tags, false) 27 | 28 | dynamic "responders" { 29 | for_each = try(each.value.responders, []) 30 | 31 | content { 32 | type = responders.value.type 33 | 34 | id = lookup(responders.value, "id", null) != null ? responders.value.id : ( 35 | responders.value.type == "team" ? try(opsgenie_team.this[responders.value.team_name].id, data.opsgenie_team.this[responders.value.team_name].id) : ( 36 | responders.value.type == "user" ? try(opsgenie_user.this[responders.value.user_name].id, data.opsgenie_user.this[responders.value.user_name].id) : ( 37 | responders.value.type == "escalation" ? opsgenie_escalation.this[responders.value.escalation_name].id : ( 38 | null 39 | ) 40 | ) 41 | ) 42 | ) 43 | 44 | name = try(responders.value.name, null) 45 | username = try(responders.value.username, null) 46 | } 47 | } 48 | 49 | filter { 50 | type = try(each.value.filter.type, "match-all") 51 | 52 | dynamic "conditions" { 53 | for_each = try(each.value.filter.conditions, []) 54 | 55 | content { 56 | expected_value = try(conditions.value.expected_value, null) 57 | field = try(conditions.value.field, null) 58 | key = try(conditions.value.key, null) 59 | not = try(conditions.value.not, null) 60 | operation = try(conditions.value.operation, null) 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /modules/config/api_integrations.tf: -------------------------------------------------------------------------------- 1 | resource "opsgenie_api_integration" "this" { 2 | for_each = module.this.enabled ? { for integration in local.api_integrations : integration.name => integration } : {} 3 | 4 | name = each.value.name 5 | type = each.value.type 6 | 7 | dynamic "responders" { 8 | for_each = try(each.value.responders, []) 9 | 10 | content { 11 | type = responders.value.type 12 | id = responders.value.id 13 | } 14 | } 15 | 16 | enabled = try(each.value.enabled, true) 17 | allow_write_access = try(each.value.allow_write_access, true) 18 | ignore_responders_from_payload = try(each.value.ignore_responders_from_payload, false) 19 | suppress_notifications = try(each.value.suppress_notifications, false) 20 | webhook_url = try(each.value.webhook_url, null) 21 | 22 | # Look up our team id by name 23 | owner_team_id = try(opsgenie_team.this[each.value.owner_team_name].id, data.opsgenie_team.this[each.value.owner_team_name].id, null) 24 | } 25 | -------------------------------------------------------------------------------- /modules/config/escalations.tf: -------------------------------------------------------------------------------- 1 | resource "opsgenie_escalation" "this" { 2 | for_each = module.this.enabled ? { for escalation in local.escalations : escalation.name => escalation } : tomap() 3 | 4 | name = each.value.name 5 | description = try(each.value.description, each.value.name) 6 | 7 | # Look up our team id by name 8 | owner_team_id = try(opsgenie_team.this[each.value.owner_team_name].id, data.opsgenie_team.this[each.value.owner_team_name].id, null) 9 | 10 | dynamic "rules" { 11 | for_each = each.value.rules 12 | 13 | content { 14 | condition = try(rules.value.condition, "if-not-acked") 15 | notify_type = try(rules.value.notify_type, "default") 16 | delay = try(rules.value.delay, 0) 17 | 18 | recipient { 19 | type = rules.value.recipient.type 20 | id = try(rules.value.recipient.id, null) != null ? rules.value.recipient.id : ( 21 | rules.value.recipient.type == "team" ? try(opsgenie_team.this[rules.value.recipient.team_name].id, data.opsgenie_team.this[rules.value.recipient.team_name].id) : ( 22 | rules.value.recipient.type == "user" ? try(opsgenie_user.this[rules.value.recipient.user_name].id, data.opsgenie_user.this[rules.value.recipient.user_name].id) : ( 23 | rules.value.recipient.type == "schedule" ? try(opsgenie_schedule.this[rules.value.recipient.schedule_name].id, data.opsgenie_schedule.this[rules.value.recipient.schedule_name].id) : ( 24 | null 25 | ) 26 | ) 27 | ) 28 | ) 29 | } 30 | } 31 | } 32 | 33 | dynamic "repeat" { 34 | for_each = try(each.value.repeat, {}) 35 | 36 | content { 37 | wait_interval = lookup(each.value.repeat, "wait_interval", 5) 38 | count = lookup(each.value.repeat, "count", 0) 39 | reset_recipient_states = lookup(each.value.repeat, "reset_recipient_states", true) 40 | close_alert_after_all = lookup(each.value.repeat, "close_alert_after_all", true) 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /modules/config/existing_resources.tf: -------------------------------------------------------------------------------- 1 | // local.existing users is a list of key pairs, in which all keys are "username". 2 | // Let's remove duplicated items from the list based on the value of each item. 3 | // Existing schedules and teams are just a plain list of their respective 4 | // resource names. 5 | locals { 6 | distinct_existing_users = distinct([for user in local.existing_users : user.username]) 7 | unique_existing_users = [for u in local.distinct_existing_users : { "username" = u }] 8 | 9 | unique_existing_schedules = distinct(local.existing_schedules) 10 | 11 | unique_existing_teams = distinct(local.existing_teams) 12 | } 13 | 14 | data "opsgenie_user" "this" { 15 | for_each = module.this.enabled ? { for user in local.unique_existing_users : user.username => user } : tomap() 16 | 17 | username = each.value.username 18 | } 19 | 20 | data "opsgenie_schedule" "this" { 21 | for_each = module.this.enabled ? toset(local.unique_existing_schedules) : toset() 22 | 23 | name = each.key 24 | } 25 | 26 | data "opsgenie_team" "this" { 27 | for_each = module.this.enabled ? toset(local.unique_existing_teams) : toset() 28 | 29 | name = each.key 30 | } 31 | -------------------------------------------------------------------------------- /modules/config/integration_actions.tf: -------------------------------------------------------------------------------- 1 | resource "opsgenie_integration_action" "this" { 2 | for_each = { for integration_action in local.integration_actions : integration_action.name => integration_action if module.this.enabled } 3 | 4 | # Look up our integration id by name 5 | integration_id = try(opsgenie_api_integration.this[each.value.integration_name].id, null) 6 | 7 | dynamic "create" { 8 | for_each = try(each.value.create, []) 9 | 10 | content { 11 | name = try(create.value.name, null) 12 | order = try(create.value.order, null) 13 | tags = try(create.value.tags, []) 14 | user = try(create.value.user, null) 15 | note = try(create.value.note, null) 16 | alias = try(create.value.alias, null) 17 | source = try(create.value.source, null) 18 | message = try(create.value.message, null) 19 | description = try(create.value.description, null) 20 | entity = try(create.value.entity, null) 21 | alert_actions = try(create.value.alert_actions, []) 22 | extra_properties = try(create.value.extra_properties, {}) 23 | custom_priority = try(create.value.custom_priority, null) 24 | ignore_responders_from_payload = try(create.value.ignore_responders_from_payload, false) 25 | ignore_teams_from_payload = try(create.value.ignore_teams_from_payload, false) 26 | 27 | responders { 28 | id = try(opsgenie_api_integration.this[each.value.integration_name].owner_team_id, null) 29 | type = "team" 30 | } 31 | 32 | filter { 33 | type = try(create.value.filter.type, null) 34 | 35 | dynamic "conditions" { 36 | for_each = try(create.value.filter.conditions, []) 37 | 38 | content { 39 | field = try(conditions.value.field, null) 40 | not = try(conditions.value.not, null) 41 | operation = try(conditions.value.operation, null) 42 | expected_value = try(conditions.value.expected_value, null) 43 | } 44 | } 45 | } 46 | } 47 | } 48 | 49 | dynamic "close" { 50 | for_each = try(each.value.close, []) 51 | 52 | content { 53 | name = try(close.value.name, null) 54 | order = try(close.value.order, null) 55 | alias = try(close.value.alias, null) 56 | 57 | filter { 58 | type = try(close.value.filter.type, null) 59 | 60 | dynamic "conditions" { 61 | for_each = try(close.value.filter.conditions, []) 62 | 63 | content { 64 | field = try(conditions.value.field, null) 65 | not = try(conditions.value.not, null) 66 | operation = try(conditions.value.operation, null) 67 | expected_value = try(conditions.value.expected_value, null) 68 | } 69 | } 70 | } 71 | } 72 | } 73 | 74 | dynamic "acknowledge" { 75 | for_each = try(each.value.acknowledge, []) 76 | 77 | content { 78 | name = try(acknowledge.value.name, null) 79 | order = try(acknowledge.value.order, null) 80 | alias = try(acknowledge.value.alias, null) 81 | 82 | filter { 83 | type = try(acknowledge.value.filter.type, null) 84 | 85 | dynamic "conditions" { 86 | for_each = try(acknowledge.value.filter.conditions, []) 87 | 88 | content { 89 | field = try(conditions.value.field, null) 90 | not = try(conditions.value.not, null) 91 | operation = try(conditions.value.operation, null) 92 | expected_value = try(conditions.value.expected_value, null) 93 | } 94 | } 95 | } 96 | } 97 | } 98 | 99 | dynamic "add_note" { 100 | for_each = try(each.value.add_note, []) 101 | 102 | content { 103 | name = try(add_note.value.name, null) 104 | order = try(add_note.value.order, null) 105 | alias = try(add_note.value.alias, null) 106 | note = try(add_note.value.name, null) 107 | 108 | filter { 109 | type = try(add_note.value.filter.type, null) 110 | 111 | dynamic "conditions" { 112 | for_each = try(add_note.value.filter.conditions, []) 113 | 114 | content { 115 | field = try(conditions.value.field, null) 116 | not = try(conditions.value.not, null) 117 | operation = try(conditions.value.operation, null) 118 | expected_value = try(conditions.value.expected_value, null) 119 | } 120 | } 121 | } 122 | } 123 | } 124 | 125 | dynamic "ignore" { 126 | for_each = try(each.value.ignore, []) 127 | 128 | content { 129 | name = try(ignore.value.name, null) 130 | order = try(ignore.value.order, null) 131 | 132 | filter { 133 | type = try(ignore.value.filter.type, null) 134 | 135 | dynamic "conditions" { 136 | for_each = try(ignore.value.filter.conditions, []) 137 | 138 | content { 139 | field = try(conditions.value.field, null) 140 | not = try(conditions.value.not, null) 141 | operation = try(conditions.value.operation, null) 142 | expected_value = try(conditions.value.expected_value, null) 143 | } 144 | } 145 | } 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /modules/config/main.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | alert_policies = lookup(var.opsgenie_resources, "alert_policies", []) 3 | api_integrations = lookup(var.opsgenie_resources, "api_integrations", []) 4 | escalations = lookup(var.opsgenie_resources, "escalations", []) 5 | integration_actions = lookup(var.opsgenie_resources, "integration_actions", []) 6 | notification_policies = lookup(var.opsgenie_resources, "notification_policies", []) 7 | schedules = lookup(var.opsgenie_resources, "schedules", []) 8 | existing_schedules = lookup(var.opsgenie_resources, "existing_schedules", []) 9 | schedule_rotations = lookup(var.opsgenie_resources, "schedule_rotations", []) 10 | team_routing_rules = lookup(var.opsgenie_resources, "team_routing_rules", []) 11 | teams = lookup(var.opsgenie_resources, "teams", []) 12 | existing_teams = lookup(var.opsgenie_resources, "existing_teams", []) 13 | users = lookup(var.opsgenie_resources, "users", []) 14 | existing_users = lookup(var.opsgenie_resources, "existing_users", []) 15 | services = lookup(var.opsgenie_resources, "services", []) 16 | service_incident_rules = lookup(var.opsgenie_resources, "service_incident_rules", []) 17 | } 18 | -------------------------------------------------------------------------------- /modules/config/notification_policies.tf: -------------------------------------------------------------------------------- 1 | resource "opsgenie_notification_policy" "this" { 2 | for_each = module.this.enabled ? { for policy in local.notification_policies : policy.name => policy } : tomap() 3 | 4 | enabled = try(each.value.enabled, true) 5 | name = each.key 6 | 7 | # Look up our team id by name 8 | team_id = try(opsgenie_team.this[each.value.team_name].id, data.opsgenie_team.this[each.value.team_name].id) 9 | policy_description = try(each.value.description, each.value.name) 10 | 11 | filter { 12 | type = try(each.value.filter.type, "match-all") 13 | 14 | dynamic "conditions" { 15 | for_each = try(each.value.filter.conditions, []) 16 | 17 | content { 18 | field = conditions.value.field 19 | operation = conditions.value.operation 20 | expected_value = try(conditions.value.expected_value, "") 21 | key = try(conditions.value.key, null) 22 | not = try(conditions.value.not, false) 23 | order = try(conditions.value.order, null) 24 | } 25 | } 26 | } 27 | 28 | dynamic "time_restriction" { 29 | for_each = try(each.value.time_restriction, null) != null ? [each.value.time_restriction] : [] 30 | 31 | content { 32 | type = time_restriction.value.type 33 | 34 | dynamic "restrictions" { 35 | for_each = try(time_restriction.value.restrictions, null) != null ? [time_restriction.value.restrictions] : [] 36 | 37 | content { 38 | start_day = restrictions.value.start_day 39 | end_day = restrictions.value.end_day 40 | start_hour = restrictions.value.start_hour 41 | end_hour = restrictions.value.end_hour 42 | start_min = restrictions.value.start_min 43 | end_min = restrictions.value.end_min 44 | } 45 | } 46 | 47 | dynamic "restriction" { 48 | for_each = try(time_restriction.value.restriction, null) != null ? [time_restriction.value.restriction] : [] 49 | 50 | content { 51 | start_hour = restriction.value.start_hour 52 | end_hour = restriction.value.end_hour 53 | start_min = restriction.value.start_min 54 | end_min = restriction.value.end_min 55 | } 56 | } 57 | } 58 | } 59 | 60 | dynamic "auto_close_action" { 61 | for_each = try(each.value.auto_close_action, null) != null ? [each.value.auto_close_action] : [] 62 | 63 | content { 64 | duration { 65 | time_amount = auto_close_action.value.duration.time_amount 66 | time_unit = try(auto_close_action.value.duration.time_unit, "minutes") 67 | } 68 | } 69 | 70 | } 71 | 72 | dynamic "auto_restart_action" { 73 | for_each = try(each.value.auto_restart_action, null) != null ? [each.value.auto_restart_action] : [] 74 | 75 | content { 76 | duration { 77 | time_amount = auto_restart_action.value.duration.time_amount 78 | time_unit = try(auto_restart_action.value.duration.time_unit, "minutes") 79 | } 80 | max_repeat_count = auto_restart_action.value.max_repeat_count 81 | } 82 | 83 | } 84 | 85 | dynamic "de_duplication_action" { 86 | for_each = try(each.value.de_duplication_action, null) != null ? [each.value.de_duplication_action] : [] 87 | 88 | content { 89 | de_duplication_action_type = de_duplication_action.value.de_duplication_action_type 90 | count = de_duplication_action.value.count 91 | 92 | dynamic "duration" { 93 | for_each = de_duplication_action.value.de_duplication_action_type == "frequency-based" ? [de_duplication_action.value.duration] : [try(de_duplication_action.value.duration, null)] 94 | 95 | content { 96 | time_amount = duration.value.time_amount 97 | time_unit = try(duration.value.time_unit, "minutes") 98 | } 99 | } 100 | } 101 | } 102 | 103 | dynamic "delay_action" { 104 | for_each = try(each.value.delay_action, null) != null ? [each.value.delay_action] : [] 105 | 106 | content { 107 | delay_option = delay_action.value.delay_option 108 | 109 | dynamic "duration" { 110 | for_each = delay_action.value.delay_option == "for-duration" ? [delay_action.value.duration] : [] 111 | 112 | content { 113 | time_amount = duration.value.time_amount 114 | time_unit = try(duration.value.time_unit, "minutes") 115 | } 116 | } 117 | 118 | until_hour = delay_action.value.delay_option != "for-duration" ? delay_action.value.until_hour : null 119 | until_minute = delay_action.value.delay_option != "for-duration" ? delay_action.value.until_minute : null 120 | } 121 | } 122 | 123 | suppress = try(each.value.suppress, null) 124 | } 125 | -------------------------------------------------------------------------------- /modules/config/outputs.tf: -------------------------------------------------------------------------------- 1 | output "alert_policies" { 2 | value = { 3 | for policy in opsgenie_alert_policy.this : policy.id => policy.name 4 | } 5 | description = "Alert policies" 6 | } 7 | 8 | output "api_integrations" { 9 | value = { 10 | for integration in opsgenie_api_integration.this : integration.id => integration.name 11 | } 12 | description = "API integrations" 13 | } 14 | 15 | output "api_integration_keys" { 16 | value = { 17 | for integration in opsgenie_api_integration.this : integration.name => integration.api_key 18 | } 19 | description = "A map of Opsgenie API integration names and generated API keys" 20 | sensitive = true 21 | } 22 | 23 | output "escalations" { 24 | value = { 25 | for escalation in opsgenie_escalation.this : escalation.id => escalation.name 26 | } 27 | description = "Escalations" 28 | } 29 | 30 | output "integration_actions" { 31 | value = [ 32 | for integration_action in opsgenie_integration_action.this : integration_action.id 33 | ] 34 | description = "Integration Actions" 35 | } 36 | 37 | output "notification_policies" { 38 | value = { 39 | for policy in opsgenie_notification_policy.this : policy.id => policy.name 40 | } 41 | description = "Notification policies" 42 | } 43 | 44 | output "schedules" { 45 | value = { 46 | for schedule in opsgenie_schedule.this : schedule.id => schedule.name 47 | } 48 | description = "Schedules" 49 | } 50 | 51 | output "schedule_rotations" { 52 | value = { 53 | for rotation in opsgenie_schedule_rotation.this : rotation.id => rotation.name 54 | } 55 | description = "Schedule rotations" 56 | } 57 | 58 | output "team_routing_rules" { 59 | value = { 60 | for rule in opsgenie_team_routing_rule.this : rule.id => rule.name 61 | } 62 | description = "Team routing rules" 63 | } 64 | 65 | output "teams" { 66 | value = { 67 | for team in opsgenie_team.this : team.id => team.name 68 | } 69 | description = "Teams" 70 | } 71 | 72 | output "users" { 73 | value = { 74 | for user in opsgenie_user.this : user.id => user.username 75 | } 76 | description = "Users" 77 | } 78 | 79 | output "existing_users" { 80 | value = { 81 | for user in data.opsgenie_user.this : user.id => user.username 82 | } 83 | description = "Users that already exist in Opsgenie" 84 | } 85 | 86 | output "services" { 87 | value = { 88 | for service in opsgenie_service.this : service.id => service.name 89 | } 90 | description = "Services" 91 | } 92 | 93 | output "service_incident_rule_ids" { 94 | value = [ 95 | for service_incident_rule in opsgenie_service_incident_rule.this : service_incident_rule.id 96 | ] 97 | description = "Service Incident Rule IDs" 98 | } 99 | -------------------------------------------------------------------------------- /modules/config/schedule_rotations.tf: -------------------------------------------------------------------------------- 1 | resource "opsgenie_schedule_rotation" "this" { 2 | for_each = module.this.enabled ? { for schedule_rotation in local.schedule_rotations : schedule_rotation.name => schedule_rotation } : tomap() 3 | 4 | name = each.value.name 5 | type = each.value.type 6 | 7 | start_date = each.value.start_date 8 | end_date = try(each.value.end_date, null) 9 | length = try(each.value.length, null) 10 | 11 | # Look up our schedule id by name 12 | schedule_id = try(opsgenie_schedule.this[each.value.schedule_name].id, data.opsgenie_schedule.this[each.value.schedule_name].id, null) 13 | 14 | dynamic "participant" { 15 | for_each = try(each.value.participants, []) 16 | 17 | content { 18 | type = participant.value.type 19 | id = participant.value.type == "none" ? null : try(opsgenie_user.this[participant.value.username].id, data.opsgenie_user.this[participant.value.username].id) 20 | } 21 | } 22 | 23 | dynamic "time_restriction" { 24 | for_each = try(each.value.time_restriction, null) != null ? ["true"] : [] 25 | 26 | content { 27 | type = each.value.time_restriction.type 28 | 29 | dynamic "restriction" { 30 | for_each = each.value.time_restriction.type == "time-of-day" ? each.value.time_restriction.restrictions : [] 31 | 32 | content { 33 | start_hour = restriction.value.start_hour 34 | start_min = restriction.value.start_min 35 | end_hour = restriction.value.end_hour 36 | end_min = restriction.value.end_min 37 | } 38 | } 39 | 40 | dynamic "restrictions" { 41 | for_each = each.value.time_restriction.type == "weekday-and-time-of-day" ? each.value.time_restriction.restrictions : [] 42 | 43 | content { 44 | start_day = restrictions.value.start_day 45 | end_day = restrictions.value.end_day 46 | start_hour = restrictions.value.start_hour 47 | start_min = restrictions.value.start_min 48 | end_hour = restrictions.value.end_hour 49 | end_min = restrictions.value.end_min 50 | } 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /modules/config/schedules.tf: -------------------------------------------------------------------------------- 1 | resource "opsgenie_schedule" "this" { 2 | for_each = module.this.enabled ? { for schedule in local.schedules : schedule.name => schedule } : tomap() 3 | 4 | enabled = try(each.value.enabled, true) 5 | 6 | name = each.value.name 7 | description = try(each.value.description, each.value.name) 8 | timezone = try(each.value.timezone, each.value.name) 9 | 10 | # Look up our team id by name 11 | owner_team_id = try(opsgenie_team.this[each.value.owner_team_name].id, data.opsgenie_team.this[each.value.owner_team_name].id, null) 12 | } 13 | -------------------------------------------------------------------------------- /modules/config/service_incident_rules.tf: -------------------------------------------------------------------------------- 1 | resource "opsgenie_service_incident_rule" "this" { 2 | for_each = module.this.enabled ? { for service_incident_rule in local.service_incident_rules : service_incident_rule.name => service_incident_rule } : tomap() 3 | 4 | service_id = opsgenie_service.this[each.value.service_name].id 5 | 6 | incident_rule { 7 | condition_match_type = try(each.value.incident_rule.condition_match_type, "match-all") 8 | 9 | dynamic "conditions" { 10 | for_each = try(each.value.incident_rule.conditions, []) 11 | 12 | content { 13 | expected_value = try(conditions.value.expected_value, null) 14 | field = conditions.value.field 15 | not = try(conditions.value.not, null) 16 | operation = conditions.value.operation 17 | } 18 | } 19 | 20 | incident_properties { 21 | message = each.value.incident_rule.incident_properties.message 22 | priority = each.value.incident_rule.incident_properties.priority 23 | tags = try(each.value.incident_rule.incident_properties.tags, null) 24 | details = try(each.value.incident_rule.incident_properties.details, null) 25 | 26 | stakeholder_properties { 27 | message = each.value.incident_rule.incident_properties.stakeholder_properties.message 28 | description = try(each.value.incident_rule.incident_properties.stakeholder_properties.description, null) 29 | enable = try(each.value.incident_rule.incident_properties.stakeholder_properties.enable, null) 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /modules/config/services.tf: -------------------------------------------------------------------------------- 1 | resource "opsgenie_service" "this" { 2 | for_each = module.this.enabled ? { for service in local.services : service.name => service } : tomap() 3 | 4 | name = each.value.name 5 | team_id = try(opsgenie_team.this[each.value.team_name].id, data.opsgenie_team.this[each.value.team_name].id) 6 | description = try(each.value.description, null) 7 | } 8 | -------------------------------------------------------------------------------- /modules/config/team_routing_rules.tf: -------------------------------------------------------------------------------- 1 | resource "opsgenie_team_routing_rule" "this" { 2 | for_each = module.this.enabled ? { for rule in local.team_routing_rules : rule.name => rule } : tomap() 3 | 4 | name = each.value.name 5 | 6 | is_default = try(each.value.is_default, false) 7 | 8 | # Look up Team ID by name 9 | team_id = try(opsgenie_team.this[each.value.owner_team_name].id, data.opsgenie_team.this[each.value.owner_team_name].id) 10 | 11 | order = try(each.value.order, 0) 12 | timezone = try(each.value.timezone, "America/Los_Angeles") 13 | 14 | dynamic "criteria" { 15 | for_each = try(each.value.criteria, null) != null ? ["true"] : [] 16 | 17 | content { 18 | type = lookup(each.value.criteria, "type", "match-all") 19 | 20 | dynamic "conditions" { 21 | for_each = lookup(each.value.criteria, "conditions", []) 22 | 23 | content { 24 | expected_value = try(conditions.value.expected_value, null) 25 | field = try(conditions.value.field, null) 26 | key = try(conditions.value.key, null) 27 | not = try(conditions.value.not, null) 28 | operation = try(conditions.value.operation, null) 29 | order = try(conditions.value.order, null) 30 | } 31 | } 32 | } 33 | } 34 | 35 | dynamic "notify" { 36 | for_each = try(each.value.notify, []) 37 | 38 | content { 39 | type = notify.value.type 40 | id = opsgenie_escalation.this[notify.value.name].id 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /modules/config/teams.tf: -------------------------------------------------------------------------------- 1 | resource "opsgenie_team" "this" { 2 | for_each = module.this.enabled ? { for team in local.teams : team.name => team } : tomap() 3 | 4 | name = each.value.name 5 | description = try(each.value.description, each.value.name) 6 | ignore_members = try(each.value.ignore_members, false) 7 | delete_default_resources = try(each.value.delete_default_resources, false) 8 | 9 | dynamic "member" { 10 | for_each = try(tolist(each.value.members), []) 11 | 12 | content { 13 | id = try(opsgenie_user.this[member.value.username].id, data.opsgenie_user.this[member.value.username].id) 14 | role = try(member.value.role, null) 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /modules/config/users.tf: -------------------------------------------------------------------------------- 1 | resource "opsgenie_user" "this" { 2 | for_each = module.this.enabled ? { for user in local.users : user.username => user } : tomap() 3 | 4 | username = each.value.username 5 | full_name = each.value.full_name 6 | role = each.value.role 7 | locale = try(each.value.locale, "en_US") 8 | timezone = try(each.value.timezone, "America/New_York") 9 | } 10 | -------------------------------------------------------------------------------- /modules/config/variables.tf: -------------------------------------------------------------------------------- 1 | variable "opsgenie_resources" { 2 | default = {} 3 | description = "Map that contains all Opsgenie resource definitions" 4 | } 5 | -------------------------------------------------------------------------------- /modules/config/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13.0" 3 | 4 | required_providers { 5 | opsgenie = { 6 | source = "opsgenie/opsgenie" 7 | version = ">= 0.4" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/escalation/README.md: -------------------------------------------------------------------------------- 1 | ## Escalation 2 | 3 | Terraform module to configure [Opsgenie Escalation](https://registry.terraform.io/providers/opsgenie/opsgenie/latest/docs/resources/escalation) 4 | 5 | 6 | ## Usage 7 | 8 | [Create Opsgenie Escalation example](../../examples/escalation) 9 | 10 | ```hcl 11 | module "escalation" { 12 | source = "cloudposse/incident-management/opsgenie//modules/escalation" 13 | # Cloud Posse recommends pinning every module to a specific version 14 | # version = "x.x.x" 15 | 16 | escalation = { 17 | name = module.label.id 18 | owner_team_id = module.owner_team.team_id 19 | 20 | rules = [{ 21 | recipient = { 22 | type = "team" 23 | id = module.escalation_team.team_id 24 | } 25 | }] 26 | } 27 | 28 | } 29 | 30 | ``` 31 | 32 | ## Inputs 33 | 34 | **Note:** `escalation` is a map for two reasons: 35 | - to be able to put whole configuration in yaml file 36 | - variables defined with type set are not robust enough (can't set default values) 37 | 38 | | Name | Default | Description | Required | 39 | |:-------------------------------|:---------------------------------:|:--------------------------------------------------------------------------------------------------------------------------------|:--------:| 40 | | `escalation` | `{}` | This variable is used to configure Opsgenie Escalation. | Yes | 41 | 42 | 43 | ## Outputs 44 | 45 | | Name | Description | 46 | |:----------------------------|:-----------------------------------------| 47 | | `escalation_name` | The name of the Opsgenie Escalation.| 48 | | `escalation_id` | The ID of the Opsgenie Escalation. | 49 | -------------------------------------------------------------------------------- /modules/escalation/main.tf: -------------------------------------------------------------------------------- 1 | resource "opsgenie_escalation" "this" { 2 | count = module.this.enabled ? 1 : 0 3 | 4 | name = var.escalation.name 5 | description = try(var.escalation.description, var.escalation.name) 6 | owner_team_id = try(var.escalation.owner_team_id, null) 7 | 8 | dynamic "rules" { 9 | for_each = var.escalation.rules 10 | 11 | content { 12 | condition = try(rules.value.condition, "if-not-acked") 13 | notify_type = try(rules.value.notify_type, "default") 14 | delay = try(rules.value.delay, 0) 15 | 16 | recipient { 17 | type = rules.value.recipient.type 18 | id = try(rules.value.recipient.id, null) 19 | } 20 | } 21 | } 22 | 23 | dynamic "repeat" { 24 | for_each = try(var.escalation.repeat, null) != null ? ["true"] : [] 25 | 26 | content { 27 | wait_interval = try(var.escalation.repeat.wait_interval, 5) 28 | count = try(var.escalation.repeat.count, 0) 29 | reset_recipient_states = try(var.escalation.repeat.reset_recipient_states, true) 30 | close_alert_after_all = try(var.escalation.repeat.close_alert_after_all, true) 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /modules/escalation/outputs.tf: -------------------------------------------------------------------------------- 1 | output "escalation_id" { 2 | description = "The ID of the Opsgenie Escalation" 3 | value = try(opsgenie_escalation.this[0].id, null) 4 | } 5 | 6 | output "escalation_name" { 7 | description = "Name of the Opsgenie Escalation" 8 | value = try(opsgenie_escalation.this[0].name, null) 9 | } 10 | -------------------------------------------------------------------------------- /modules/escalation/variables.tf: -------------------------------------------------------------------------------- 1 | variable "escalation" { 2 | default = {} 3 | description = "Opsgenie Escalation configuration" 4 | } 5 | -------------------------------------------------------------------------------- /modules/escalation/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13.0" 3 | 4 | required_providers { 5 | opsgenie = { 6 | source = "opsgenie/opsgenie" 7 | version = ">= 0.4" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/integration_action/README.md: -------------------------------------------------------------------------------- 1 | ## Integration Action 2 | 3 | Terraform module to configure [Opsgenie Integration Action](https://registry.terraform.io/providers/opsgenie/opsgenie/latest/docs/resources/integration_action) 4 | 5 | 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.`. 6 | 7 | 8 | ## Usage 9 | 10 | [Create Opsgenie Integration Action example](../../examples/integration_action) 11 | 12 | ```hcl 13 | module "integration_action" { 14 | source = "cloudposse/incident-management/opsgenie//modules/integration_action" 15 | # Cloud Posse recommends pinning every module to a specific version 16 | # version = "x.x.x" 17 | 18 | integration_action = { 19 | integration_id = module.api_integration.api_integration_id 20 | 21 | create = [ 22 | { 23 | name = "Create Non-informational Alerts" 24 | alias = "{{title}}" 25 | filter = { 26 | type = "match-all-conditions" 27 | conditions = [ 28 | { 29 | field = "priority" 30 | not = true 31 | operation = "equals" 32 | expected_value = "P5" 33 | } 34 | ] 35 | } 36 | } 37 | ] 38 | } 39 | } 40 | ``` 41 | 42 | ## Inputs 43 | 44 | **Note:** `integration_action` is a map for two reasons: 45 | - to be able to put whole configuration in yaml file 46 | - variables defined with type set are not robust enough (can't set default values) 47 | 48 | | Name | Default | Description | Required | 49 | |:-------------------------------|:---------------------------------:|:--------------------------------------------------------------------------------------------------------------------------------|:--------:| 50 | | `integration_action` | `{}` | This variable is used to configure Opsgenie Integration Action. | Yes | 51 | 52 | 53 | ## Outputs 54 | 55 | | Name | Description | 56 | |:----------------------------|:---------------------------------------------| 57 | | `integration_action_id` | The ID of the Opsgenie Integration Action. | 58 | -------------------------------------------------------------------------------- /modules/integration_action/main.tf: -------------------------------------------------------------------------------- 1 | resource "opsgenie_integration_action" "this" { 2 | count = module.this.enabled ? 1 : 0 3 | 4 | integration_id = var.integration_action.integration_id 5 | 6 | dynamic "create" { 7 | for_each = try(var.integration_action.create, []) 8 | 9 | content { 10 | name = try(create.value.name, null) 11 | order = try(create.value.order, null) 12 | tags = try(create.value.tags, []) 13 | user = try(create.value.user, null) 14 | note = try(create.value.note, null) 15 | alias = try(create.value.alias, null) 16 | source = try(create.value.source, null) 17 | message = try(create.value.message, null) 18 | description = try(create.value.description, null) 19 | entity = try(create.value.entity, null) 20 | alert_actions = try(create.value.alert_actions, []) 21 | extra_properties = try(create.value.extra_properties, {}) 22 | custom_priority = try(create.value.custom_priority, null) 23 | ignore_responders_from_payload = try(create.value.ignore_responders_from_payload, false) 24 | ignore_teams_from_payload = try(create.value.ignore_teams_from_payload, false) 25 | 26 | responders { 27 | id = var.integration_action.team_id 28 | type = "team" 29 | } 30 | 31 | filter { 32 | type = try(create.value.filter.type, null) 33 | 34 | dynamic "conditions" { 35 | for_each = try(create.value.filter.conditions, []) 36 | 37 | content { 38 | field = try(conditions.value.field, null) 39 | not = try(conditions.value.not, null) 40 | operation = try(conditions.value.operation, null) 41 | expected_value = try(conditions.value.expected_value, null) 42 | } 43 | } 44 | } 45 | } 46 | } 47 | 48 | dynamic "close" { 49 | for_each = try(var.integration_action.close, []) 50 | 51 | content { 52 | name = try(close.value.name, null) 53 | order = try(close.value.order, null) 54 | alias = try(close.value.alias, null) 55 | 56 | filter { 57 | type = try(close.value.filter.type, null) 58 | 59 | dynamic "conditions" { 60 | for_each = try(close.value.filter.conditions, []) 61 | 62 | content { 63 | field = try(conditions.value.field, null) 64 | not = try(conditions.value.not, null) 65 | operation = try(conditions.value.operation, null) 66 | expected_value = try(conditions.value.expected_value, null) 67 | } 68 | } 69 | } 70 | } 71 | } 72 | 73 | dynamic "acknowledge" { 74 | for_each = try(var.integration_action.acknowledge, []) 75 | 76 | content { 77 | name = try(acknowledge.value.name, null) 78 | order = try(acknowledge.value.order, null) 79 | alias = try(acknowledge.value.alias, null) 80 | 81 | filter { 82 | type = try(acknowledge.value.filter.type, null) 83 | 84 | dynamic "conditions" { 85 | for_each = try(acknowledge.value.filter.conditions, []) 86 | 87 | content { 88 | field = try(conditions.value.field, null) 89 | not = try(conditions.value.not, null) 90 | operation = try(conditions.value.operation, null) 91 | expected_value = try(conditions.value.expected_value, null) 92 | } 93 | } 94 | } 95 | } 96 | } 97 | 98 | dynamic "add_note" { 99 | for_each = try(var.integration_action.add_note, []) 100 | 101 | content { 102 | name = try(add_note.value.name, null) 103 | order = try(add_note.value.order, null) 104 | alias = try(add_note.value.alias, null) 105 | note = try(add_note.value.name, null) 106 | 107 | filter { 108 | type = try(add_note.value.filter.type, null) 109 | 110 | dynamic "conditions" { 111 | for_each = try(add_note.value.filter.conditions, []) 112 | 113 | content { 114 | field = try(conditions.value.field, null) 115 | not = try(conditions.value.not, null) 116 | operation = try(conditions.value.operation, null) 117 | expected_value = try(conditions.value.expected_value, null) 118 | } 119 | } 120 | } 121 | } 122 | } 123 | 124 | dynamic "ignore" { 125 | for_each = try(var.integration_action.ignore, []) 126 | 127 | content { 128 | name = try(ignore.value.name, null) 129 | order = try(ignore.value.order, null) 130 | 131 | filter { 132 | type = try(ignore.value.filter.type, null) 133 | 134 | dynamic "conditions" { 135 | for_each = try(ignore.value.filter.conditions, []) 136 | 137 | content { 138 | field = try(conditions.value.field, null) 139 | not = try(conditions.value.not, null) 140 | operation = try(conditions.value.operation, null) 141 | expected_value = try(conditions.value.expected_value, null) 142 | } 143 | } 144 | } 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /modules/integration_action/outputs.tf: -------------------------------------------------------------------------------- 1 | output "integration_action_id" { 2 | description = "The ID of the Opsgenie Integration Action" 3 | value = try(opsgenie_integration_action.this[0].id, null) 4 | } 5 | -------------------------------------------------------------------------------- /modules/integration_action/variables.tf: -------------------------------------------------------------------------------- 1 | variable "integration_action" { 2 | default = {} 3 | description = "Opsgenie Integration Action configuration" 4 | } 5 | -------------------------------------------------------------------------------- /modules/integration_action/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13.0" 3 | 4 | required_providers { 5 | opsgenie = { 6 | source = "opsgenie/opsgenie" 7 | version = ">= 0.4" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/notification_policy/README.md: -------------------------------------------------------------------------------- 1 | ## Notification Policy 2 | 3 | Terraform module to configure [Opsgenie Notification Policy](https://registry.terraform.io/providers/opsgenie/opsgenie/latest/docs/resources/notification_policy) 4 | 5 | 6 | ## Usage 7 | 8 | [Create Opsgenie Notification Policy example](../../examples/notification_policy) 9 | 10 | ```hcl 11 | module "notification_policy" { 12 | source = "cloudposse/incident-management/opsgenie//modules/notification_policy" 13 | # Cloud Posse recommends pinning every module to a specific version 14 | # version = "x.x.x" 15 | 16 | notification_policy = { 17 | name = module.label.id 18 | team_id = module.team.team_id 19 | 20 | filter = { 21 | type = "match-all-conditions" 22 | conditions = [{ 23 | field = "tags" 24 | operation = "contains" 25 | expected_value = "recommendation:auto-close" 26 | }] 27 | } 28 | 29 | de_duplication_action = { 30 | de_duplication_action_type = "frequency-based" 31 | count = 2 32 | duration = { 33 | time_unit = "minutes" 34 | time_amount = 5 35 | } 36 | } 37 | 38 | delay_action = { 39 | delay_option = "for-duration" 40 | duration = { 41 | time_unit = "minutes" 42 | time_amount = 10 43 | } 44 | } 45 | 46 | auto_close_action = { 47 | time_unit = "minutes" 48 | time_amount = 5 49 | } 50 | } 51 | } 52 | ``` 53 | 54 | ## Inputs 55 | 56 | **Note:** `notification_policy` is a map for two reasons: 57 | - to be able to put whole configuration in yaml file 58 | - variables defined with type set are not robust enough (can't set default values) 59 | 60 | | Name | Default | Description | Required | 61 | |:-------------------------------|:---------------------------------:|:--------------------------------------------------------------------------------------------------------------------------------|:--------:| 62 | | `notification_policy` | `{}` | This variable is used to configure Opsgenie Notification Policy. | Yes | 63 | 64 | 65 | ## Outputs 66 | 67 | | Name | Description | 68 | |:----------------------------|:---------------------------------------------| 69 | | `notification_policy_name` | The name of the Opsgenie Notification Policy.| 70 | | `notification_policy_id` | The ID of the Opsgenie Notification Policy. | 71 | -------------------------------------------------------------------------------- /modules/notification_policy/main.tf: -------------------------------------------------------------------------------- 1 | resource "opsgenie_notification_policy" "this" { 2 | count = module.this.enabled ? 1 : 0 3 | 4 | enabled = try(var.notification_policy.enabled, true) 5 | name = var.notification_policy.name 6 | 7 | # Look up our team id by name 8 | team_id = var.notification_policy.team_id 9 | policy_description = try(var.notification_policy.description, var.notification_policy.name) 10 | 11 | filter { 12 | type = try(var.notification_policy.filter.type, "match-all") 13 | 14 | dynamic "conditions" { 15 | for_each = try(var.notification_policy.filter.conditions, []) 16 | 17 | content { 18 | field = conditions.value.field 19 | operation = conditions.value.operation 20 | expected_value = try(conditions.value.expected_value, "") 21 | key = try(conditions.value.key, null) 22 | not = try(conditions.value.not, false) 23 | order = try(conditions.value.order, null) 24 | } 25 | } 26 | } 27 | 28 | dynamic "time_restriction" { 29 | for_each = try(var.notification_policy.time_restriction, null) != null ? [var.notification_policy.time_restriction] : [] 30 | 31 | content { 32 | type = time_restriction.value.type 33 | 34 | dynamic "restrictions" { 35 | for_each = try(time_restriction.value.restrictions, null) != null ? [time_restriction.value.restrictions] : [] 36 | 37 | content { 38 | start_day = restrictions.value.start_day 39 | end_day = restrictions.value.end_day 40 | start_hour = restrictions.value.start_hour 41 | end_hour = restrictions.value.end_hour 42 | start_min = restrictions.value.start_min 43 | end_min = restrictions.value.end_min 44 | } 45 | } 46 | 47 | dynamic "restriction" { 48 | for_each = try(time_restriction.value.restriction, null) != null ? [time_restriction.value.restriction] : [] 49 | 50 | content { 51 | start_hour = restriction.value.start_hour 52 | end_hour = restriction.value.end_hour 53 | start_min = restriction.value.start_min 54 | end_min = restriction.value.end_min 55 | } 56 | } 57 | } 58 | } 59 | 60 | dynamic "auto_close_action" { 61 | for_each = try(var.notification_policy.auto_close_action, null) != null ? [var.notification_policy.auto_close_action] : [] 62 | 63 | content { 64 | duration { 65 | time_amount = auto_close_action.value.duration.time_amount 66 | time_unit = try(auto_close_action.value.duration.time_unit, "minutes") 67 | } 68 | } 69 | 70 | } 71 | 72 | dynamic "auto_restart_action" { 73 | for_each = try(var.notification_policy.auto_restart_action, null) != null ? [var.notification_policy.auto_restart_action] : [] 74 | 75 | content { 76 | duration { 77 | time_amount = auto_restart_action.value.duration.time_amount 78 | time_unit = try(auto_restart_action.value.duration.time_unit, "minutes") 79 | } 80 | max_repeat_count = auto_restart_action.value.max_repeat_count 81 | } 82 | 83 | } 84 | 85 | dynamic "de_duplication_action" { 86 | for_each = try(var.notification_policy.de_duplication_action, null) != null ? [var.notification_policy.de_duplication_action] : [] 87 | 88 | content { 89 | de_duplication_action_type = de_duplication_action.value.de_duplication_action_type 90 | count = de_duplication_action.value.count 91 | 92 | dynamic "duration" { 93 | for_each = de_duplication_action.value.de_duplication_action_type == "frequency-based" ? [de_duplication_action.value.duration] : [try(de_duplication_action.value.duration, null)] 94 | 95 | content { 96 | time_amount = duration.value.time_amount 97 | time_unit = try(duration.value.time_unit, "minutes") 98 | } 99 | } 100 | } 101 | } 102 | 103 | dynamic "delay_action" { 104 | for_each = try(var.notification_policy.delay_action, null) != null ? [var.notification_policy.delay_action] : [] 105 | 106 | content { 107 | delay_option = delay_action.value.delay_option 108 | 109 | dynamic "duration" { 110 | for_each = delay_action.value.delay_option == "for-duration" ? [delay_action.value.duration] : [] 111 | 112 | content { 113 | time_amount = duration.value.time_amount 114 | time_unit = try(duration.value.time_unit, "minutes") 115 | } 116 | } 117 | 118 | until_hour = delay_action.value.delay_option != "for-duration" ? delay_action.value.until_hour : null 119 | until_minute = delay_action.value.delay_option != "for-duration" ? delay_action.value.until_minute : null 120 | } 121 | } 122 | 123 | suppress = try(var.notification_policy.suppress, null) 124 | } 125 | -------------------------------------------------------------------------------- /modules/notification_policy/outputs.tf: -------------------------------------------------------------------------------- 1 | output "notification_policy_id" { 2 | description = "The ID of the Opsgenie Notification Policy" 3 | value = try(opsgenie_notification_policy.this[0].id, null) 4 | } 5 | 6 | output "notification_policy_name" { 7 | description = "The name of the Opsgenie Notification Policy" 8 | value = try(opsgenie_notification_policy.this[0].name, null) 9 | } 10 | -------------------------------------------------------------------------------- /modules/notification_policy/variables.tf: -------------------------------------------------------------------------------- 1 | variable "notification_policy" { 2 | default = {} 3 | description = "Opsgenie Notification Policy configuration" 4 | } 5 | -------------------------------------------------------------------------------- /modules/notification_policy/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13.0" 3 | 4 | required_providers { 5 | opsgenie = { 6 | source = "opsgenie/opsgenie" 7 | version = ">= 0.4" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/schedule/README.md: -------------------------------------------------------------------------------- 1 | ## schedule 2 | 3 | Terraform module to configure [Opsgenie Schedule](https://registry.terraform.io/providers/opsgenie/opsgenie/latest/docs/resources/schedule) 4 | 5 | 6 | ## Usage 7 | 8 | [Opsgenie Schedule example](../../examples/schedule) 9 | 10 | ```hcl 11 | module "schedule" { 12 | source = "cloudposse/incident-management/opsgenie//modules/schedule" 13 | # Cloud Posse recommends pinning every module to a specific version 14 | # version = "x.x.x" 15 | 16 | schedule = { 17 | name = module.label.id 18 | description = "schedule-description" 19 | } 20 | } 21 | 22 | data "opsgenie_team" "the_team" { 23 | name = var.team_name 24 | } 25 | 26 | module "team_schedule" { 27 | 28 | source = "cloudposse/incident-management/opsgenie//modules/schedule" 29 | # Cloud Posse recommends pinning every module to a specific version 30 | # version = "x.x.x" 31 | 32 | schedule = { 33 | name = module.label.id 34 | description = "team-schedule-description" 35 | owner_team_id = data.opsgenie_team.the_team.id 36 | } 37 | } 38 | ``` 39 | 40 | ## Inputs 41 | 42 | **Note:** `schedule` is a map for two reasons: 43 | - to be able to put whole configuration in yaml file 44 | - variables defined with type set are not robust enough (can't set default values) 45 | 46 | | Name | Default | Description | Required | 47 | |:-------------------------------|:---------------------------------:|:--------------------------------------------------------------------------------------------------------------------------------|:--------:| 48 | | `schedule` | `{}` | This variable is used to configure Opsgenie schedule. | Yes | 49 | 50 | 51 | ## Outputs 52 | 53 | | Name | Description | 54 | |:----------------------------|:-----------------------------------------| 55 | | `schedule_name` | The name of the Opsgenie schedule. | 56 | | `schedule_id` | The ID of the Opsgenie schedule. | 57 | -------------------------------------------------------------------------------- /modules/schedule/main.tf: -------------------------------------------------------------------------------- 1 | resource "opsgenie_schedule" "default" { 2 | count = module.this.enabled ? 1 : 0 3 | 4 | name = var.schedule.name 5 | description = try(var.schedule.description, null) 6 | owner_team_id = try(var.schedule.owner_team_id, null) 7 | 8 | enabled = try(var.schedule.enabled, null) # this is the state of the schedule, NOT module.this.enabled 9 | timezone = try(var.schedule.timezone, null) 10 | } 11 | -------------------------------------------------------------------------------- /modules/schedule/outputs.tf: -------------------------------------------------------------------------------- 1 | output "schedule_id" { 2 | description = "The ID of the Opsgenie Schedule" 3 | value = try(opsgenie_schedule.default[0].id, null) 4 | } 5 | -------------------------------------------------------------------------------- /modules/schedule/variables.tf: -------------------------------------------------------------------------------- 1 | variable "schedule" { 2 | type = map(any) 3 | default = {} 4 | description = "Opsgenie Schedule configuration" 5 | } 6 | -------------------------------------------------------------------------------- /modules/schedule/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13.0" 3 | 4 | required_providers { 5 | opsgenie = { 6 | source = "opsgenie/opsgenie" 7 | version = ">= 0.6.7" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/service/README.md: -------------------------------------------------------------------------------- 1 | ## Service 2 | 3 | Terraform module to configure [Opsgenie Service](https://registry.terraform.io/providers/opsgenie/opsgenie/latest/docs/resources/service) 4 | 5 | 6 | ## Usage 7 | 8 | ```hcl 9 | module "service" { 10 | source = "cloudposse/incident-management/opsgenie//modules/service" 11 | # Cloud Posse recommends pinning every module to a specific version 12 | # version = "x.x.x" 13 | 14 | service = { 15 | name = "frontend" 16 | team_id = "..." 17 | description = "My company frontend service" 18 | } 19 | } 20 | ``` 21 | 22 | ## Inputs 23 | 24 | **Note:** `service` is a map for two reasons: 25 | - to be able to put whole configuration in yaml file 26 | - variables defined with type set are not robust enough (can't set default values) 27 | 28 | | Name | Default | Description | Required | 29 | |:-------------------------------|:---------------------------------:|:--------------------------------------------------------------------------------------------------------------------------------|:--------:| 30 | | `service` | `{}` | Opsgenie Service configuration | Yes | 31 | 32 | 33 | ## Outputs 34 | 35 | | Name | Description | 36 | |:----------------------------|:-----------------------------------------| 37 | | `service_id` | The ID of the Opsgenie Service | 38 | | `service_name` | The name of the Opsgenie Service | 39 | -------------------------------------------------------------------------------- /modules/service/main.tf: -------------------------------------------------------------------------------- 1 | resource "opsgenie_service" "this" { 2 | count = module.this.enabled ? 1 : 0 3 | 4 | name = var.service.name 5 | team_id = var.service.team_id 6 | description = var.service.description 7 | } 8 | -------------------------------------------------------------------------------- /modules/service/outputs.tf: -------------------------------------------------------------------------------- 1 | output "service_id" { 2 | description = "The ID of the Opsgenie Service" 3 | value = try(opsgenie_service.this[0].id, null) 4 | } 5 | 6 | output "service_name" { 7 | description = "The name of the Opsgenie Service" 8 | value = try(opsgenie_service.this[0].name, null) 9 | } 10 | -------------------------------------------------------------------------------- /modules/service/variables.tf: -------------------------------------------------------------------------------- 1 | variable "service" { 2 | default = {} 3 | description = "Opsgenie Service configuration" 4 | } 5 | -------------------------------------------------------------------------------- /modules/service/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13.0" 3 | 4 | required_providers { 5 | opsgenie = { 6 | source = "opsgenie/opsgenie" 7 | version = ">= 0.4" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/service_incident_rule/README.md: -------------------------------------------------------------------------------- 1 | ## Service Incident Rule 2 | 3 | Terraform module to configure [Opsgenie Service Incident Rule](https://registry.terraform.io/providers/opsgenie/opsgenie/latest/docs/resources/service_incident_rule) 4 | 5 | 6 | ## Usage 7 | 8 | [Create Opsgenie Team Routing Rule example](../../examples/service_incident_rule) 9 | 10 | ```hcl 11 | module "service_incident_rule" { 12 | source = "cloudposse/incident-management/opsgenie//modules/service_incident_rule" 13 | # Cloud Posse recommends pinning every module to a specific version 14 | # version = "x.x.x" 15 | 16 | service_incident_rule = { 17 | service_id = "..." 18 | 19 | incident_rule = { 20 | condition_match_type = "match-all" 21 | 22 | conditions = [ 23 | { 24 | field = "tags" 25 | operation = "contains" 26 | expected_value = "expected1" 27 | } 28 | ] 29 | 30 | incident_properties = { 31 | message = "This is a test message" 32 | priority = "P3" 33 | 34 | stakeholder_properties = { 35 | message = "Message for stakeholders" 36 | enable = true 37 | } 38 | } 39 | } 40 | } 41 | } 42 | ``` 43 | 44 | ## Inputs 45 | 46 | **Note:** `service_incident_rule` is a map for two reasons: 47 | - to be able to put whole configuration in yaml file 48 | - variables defined with type set are not robust enough (can't set default values) 49 | 50 | | Name | Default | Description | Required | 51 | |:-------------------------------|:---------------------------------:|:-------------------------------------------------|:--------:| 52 | | `service_incident_rule` | `{}` | Opsgenie Service Incident Rule configuration | Yes | 53 | 54 | 55 | ## Outputs 56 | 57 | | Name | Description | 58 | |:------------------------------|:-----------------------------------------------| 59 | | `service_incident_rule_id` | The ID of the Opsgenie Service Incident Rule | 60 | -------------------------------------------------------------------------------- /modules/service_incident_rule/main.tf: -------------------------------------------------------------------------------- 1 | resource "opsgenie_service_incident_rule" "this" { 2 | count = module.this.enabled ? 1 : 0 3 | 4 | service_id = var.service_incident_rule.service_id 5 | 6 | incident_rule { 7 | condition_match_type = try(var.service_incident_rule.incident_rule.condition_match_type, "match-all") 8 | 9 | dynamic "conditions" { 10 | for_each = try(var.service_incident_rule.incident_rule.conditions, []) 11 | 12 | content { 13 | expected_value = try(conditions.value.expected_value, null) 14 | field = conditions.value.field 15 | not = try(conditions.value.not, null) 16 | operation = conditions.value.operation 17 | } 18 | } 19 | 20 | incident_properties { 21 | message = var.service_incident_rule.incident_rule.incident_properties.message 22 | priority = var.service_incident_rule.incident_rule.incident_properties.priority 23 | tags = try(var.service_incident_rule.incident_rule.incident_properties.tags, null) 24 | details = try(var.service_incident_rule.incident_rule.incident_properties.details, null) 25 | 26 | stakeholder_properties { 27 | message = var.service_incident_rule.incident_rule.incident_properties.stakeholder_properties.message 28 | description = try(var.service_incident_rule.incident_rule.incident_properties.stakeholder_properties.description, null) 29 | enable = try(var.service_incident_rule.incident_rule.incident_properties.stakeholder_properties.enable, null) 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /modules/service_incident_rule/outputs.tf: -------------------------------------------------------------------------------- 1 | output "service_incident_rule_id" { 2 | description = "The ID of the Opsgenie Service Incident Rule" 3 | value = try(opsgenie_service_incident_rule.this[0].id, null) 4 | } 5 | -------------------------------------------------------------------------------- /modules/service_incident_rule/variables.tf: -------------------------------------------------------------------------------- 1 | variable "service_incident_rule" { 2 | default = {} 3 | description = "Opsgenie Service Incident Rule configuration" 4 | } 5 | -------------------------------------------------------------------------------- /modules/service_incident_rule/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13.0" 3 | 4 | required_providers { 5 | opsgenie = { 6 | source = "opsgenie/opsgenie" 7 | version = ">= 0.4" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/team/README.md: -------------------------------------------------------------------------------- 1 | ## Team 2 | 3 | Terraform module to configure [Opsgenie Team](https://registry.terraform.io/providers/opsgenie/opsgenie/latest/docs/resources/team) 4 | 5 | 6 | ## Usage 7 | 8 | [Create Opsgenie Team example](../../examples/team) 9 | 10 | ```hcl 11 | module "team" { 12 | source = "cloudposse/incident-management/opsgenie//modules/team" 13 | # Cloud Posse recommends pinning every module to a specific version 14 | # version = "x.x.x" 15 | 16 | team = { 17 | name = module.label.id 18 | description = "team-description" 19 | } 20 | } 21 | 22 | module "ui_managed_team" { 23 | source = "cloudposse/incident-management/opsgenie//modules/team" 24 | # Cloud Posse recommends pinning every module to a specific version 25 | # version = "x.x.x" 26 | 27 | team = { 28 | name = module.label.id 29 | description = "team-description" 30 | delete_default_resources = true 31 | ignore_members = true 32 | } 33 | } 34 | 35 | ``` 36 | 37 | ## Inputs 38 | 39 | **Note:** `team` is a map for two reasons: 40 | - to be able to put whole configuration in yaml file 41 | - variables defined with type set are not robust enough (can't set default values) 42 | 43 | | Name | Default | Description | Required | 44 | |:-------------------------------|:---------------------------------:|:--------------------------------------------------------------------------------------------------------------------------------|:--------:| 45 | | `team` | `{}` | This variable is used to configure Opsgenie Team. | Yes | 46 | 47 | 48 | ## Outputs 49 | 50 | | Name | Description | 51 | |:----------------------------|:-----------------------------------------| 52 | | `team_name` | The name of the Opsgenie Team. | 53 | | `team_id` | The ID of the Opsgenie Team. | 54 | -------------------------------------------------------------------------------- /modules/team/main.tf: -------------------------------------------------------------------------------- 1 | resource "opsgenie_team" "this" { 2 | count = module.this.enabled ? 1 : 0 3 | 4 | name = var.team.name 5 | description = try(var.team.description, var.team.name) 6 | ignore_members = try(var.team.ignore_members, false) 7 | delete_default_resources = try(var.team.delete_default_resources, false) 8 | 9 | dynamic "member" { 10 | for_each = try(var.team.members, []) 11 | 12 | content { 13 | id = member.value.id 14 | role = member.value.role 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /modules/team/outputs.tf: -------------------------------------------------------------------------------- 1 | output "team_id" { 2 | description = "The ID of the Opsgenie Team" 3 | value = try(opsgenie_team.this[0].id, null) 4 | } 5 | 6 | output "team_name" { 7 | description = "The name of the Opsgenie Team" 8 | value = try(opsgenie_team.this[0].name, null) 9 | } 10 | -------------------------------------------------------------------------------- /modules/team/variables.tf: -------------------------------------------------------------------------------- 1 | variable "team" { 2 | default = {} 3 | description = "Opsgenie Team configuration" 4 | } 5 | -------------------------------------------------------------------------------- /modules/team/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13.0" 3 | 4 | required_providers { 5 | opsgenie = { 6 | source = "opsgenie/opsgenie" 7 | version = ">= 0.4" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/team_routing_rule/README.md: -------------------------------------------------------------------------------- 1 | ## Team Routing Rule 2 | 3 | Terraform module to configure [Opsgenie Team Routing Rule](https://registry.terraform.io/providers/opsgenie/opsgenie/latest/docs/resources/team_routing_rule) 4 | 5 | 6 | ## Usage 7 | 8 | [Create Opsgenie Team Routing Rule example](../../examples/team_routing_rule) 9 | 10 | ```hcl 11 | module "team_routing_rule" { 12 | source = "cloudposse/incident-management/opsgenie//modules/team_routing_rule" 13 | # Cloud Posse recommends pinning every module to a specific version 14 | # version = "x.x.x" 15 | 16 | team_routing_rule = { 17 | name = module.label.id 18 | team_id = module.owner_team.team_id 19 | 20 | notify = [{ 21 | type = "escalation" 22 | id = module.escalation.escalation_id 23 | }] 24 | } 25 | } 26 | ``` 27 | 28 | ## Inputs 29 | 30 | **Note:** `team_routing_rule` is a map for two reasons: 31 | - to be able to put whole configuration in yaml file 32 | - variables defined with type set are not robust enough (can't set default values) 33 | 34 | | Name | Default | Description | Required | 35 | |:-------------------------------|:---------------------------------:|:--------------------------------------------------------------------------------------------------------------------------------|:--------:| 36 | | `team_routing_rule` | `{}` | This variable is used to configure Opsgenie Team Routing Rule. | Yes | 37 | 38 | 39 | ## Outputs 40 | 41 | | Name | Description | 42 | |:----------------------------|:--------------------------------------------| 43 | | `team_routing_rule_name` | The name of the Opsgenie Team Routing Rule.| 44 | | `team_routing_rule_id` | The ID of the Opsgenie Team Routing Rule. | 45 | 46 | ## Important Note 47 | 48 | Due to the Opsgenie terraform provider issue, there is a difference in the configuration of the `time_restriction` blocks based on `type`. 49 | 50 | [Github Issue #282](https://github.com/opsgenie/terraform-provider-opsgenie/issues/282) 51 | 52 | ```hcl 53 | time_restriction { 54 | type = "time-of-day" 55 | restriction { 56 | end_hour = 17 57 | end_min = 0 58 | start_hour = 9 59 | start_min = 0 60 | } 61 | } 62 | ``` 63 | vs 64 | ```hcl 65 | time_restriction { 66 | type = "weekday-and-time-of-day" 67 | restriction { 68 | end_day = "friday" 69 | end_hour = 17 70 | end_min = 0 71 | start_day = "monday" 72 | start_hour = 9 73 | start_min = 0 74 | } 75 | } 76 | ``` 77 | -------------------------------------------------------------------------------- /modules/team_routing_rule/main.tf: -------------------------------------------------------------------------------- 1 | resource "opsgenie_team_routing_rule" "this" { 2 | count = module.this.enabled ? 1 : 0 3 | 4 | name = var.team_routing_rule.name 5 | team_id = var.team_routing_rule.team_id 6 | order = try(var.team_routing_rule.order, 5) 7 | 8 | timezone = try(var.team_routing_rule.timezone, "America/Los_Angeles") 9 | dynamic "time_restriction" { 10 | for_each = [for time_restriction in try([var.team_routing_rule.time_restriction], []) : time_restriction if time_restriction != null] 11 | 12 | content { 13 | # NOTE: The Opsgenie terraform provider appears to be inconsistent with how it uses time_restriction: 14 | # `restrictions` for type `weekday-and-time-of-day` 15 | # `restriction` for type `time-of-day` 16 | type = var.team_routing_rule.time_restriction.type 17 | dynamic "restrictions" { 18 | for_each = var.team_routing_rule.time_restriction.type == "weekday-and-time-of-day" ? try(var.team_routing_rule.time_restriction.restrictions, []) : [] 19 | content { 20 | start_hour = restrictions.value.start_hour 21 | start_min = restrictions.value.start_min 22 | start_day = restrictions.value.start_day 23 | end_hour = restrictions.value.end_hour 24 | end_min = restrictions.value.end_min 25 | end_day = restrictions.value.end_day 26 | } 27 | } 28 | 29 | dynamic "restriction" { 30 | for_each = var.team_routing_rule.time_restriction.type == "time-of-day" ? try(var.team_routing_rule.time_restriction.restrictions, []) : [] 31 | content { 32 | start_hour = restriction.value.start_hour 33 | start_min = restriction.value.start_min 34 | end_hour = restriction.value.end_hour 35 | end_min = restriction.value.end_min 36 | } 37 | } 38 | } 39 | } 40 | 41 | criteria { 42 | type = try(var.team_routing_rule.criteria.type != null ? var.team_routing_rule.criteria.type : "match-all", "match-all") 43 | 44 | dynamic "conditions" { 45 | for_each = try(var.team_routing_rule.criteria.conditions != null ? var.team_routing_rule.criteria.conditions : [], []) 46 | 47 | content { 48 | expected_value = try(conditions.value.expected_value, null) 49 | field = try(conditions.value.field, null) 50 | key = try(conditions.value.key, null) 51 | not = try(conditions.value.not, null) 52 | operation = try(conditions.value.operation, null) 53 | order = try(conditions.value.order, null) 54 | } 55 | } 56 | } 57 | 58 | dynamic "notify" { 59 | for_each = try(var.team_routing_rule.notify, []) 60 | 61 | content { 62 | type = notify.value.type 63 | # name and id parameters are mutually exclusive 64 | id = try(notify.value.id, null) 65 | name = try(notify.value.name, null) 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /modules/team_routing_rule/outputs.tf: -------------------------------------------------------------------------------- 1 | output "team_routing_rule_id" { 2 | description = "The ID of the Opsgenie Team Routing Rule" 3 | value = try(opsgenie_team_routing_rule.this[0].id, null) 4 | } 5 | 6 | output "team_routing_rule_name" { 7 | description = "The name of the Opsgenie Team Routing Rule" 8 | value = try(opsgenie_team_routing_rule.this[0].name, null) 9 | } 10 | -------------------------------------------------------------------------------- /modules/team_routing_rule/variables.tf: -------------------------------------------------------------------------------- 1 | variable "team_routing_rule" { 2 | default = {} 3 | description = "Opsgenie Team Routing Rule configuration" 4 | } 5 | -------------------------------------------------------------------------------- /modules/team_routing_rule/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13.0" 3 | 4 | required_providers { 5 | opsgenie = { 6 | source = "opsgenie/opsgenie" 7 | version = ">= 0.6.7" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/user/README.md: -------------------------------------------------------------------------------- 1 | ## User 2 | 3 | Terraform module to configure [Opsgenie User](https://registry.terraform.io/providers/opsgenie/opsgenie/latest/docs/resources/user) 4 | 5 | 6 | ## Usage 7 | 8 | [Create Opsgenie User example](../../examples/user) 9 | 10 | ```hcl 11 | module "user" { 12 | source = "cloudposse/incident-management/opsgenie//modules/user" 13 | # Cloud Posse recommends pinning every module to a specific version 14 | # version = "x.x.x" 15 | 16 | user = { 17 | username = "opsgenie-test@cloudposse.com" 18 | full_name = "Opsgenie Test User" 19 | role = "User" 20 | locale = "en_US" 21 | timezone = "America/New_York" 22 | } 23 | } 24 | ``` 25 | 26 | ## Inputs 27 | 28 | **Note:** `user` is a map for two reasons: 29 | - to be able to put whole configuration in yaml file 30 | - variables defined with type set are not robust enough (can't set default values) 31 | 32 | | Name | Default | Description | Required | 33 | |:-------------------------------|:---------------------------------:|:--------------------------------------------------------------------------------------------------------------------------------|:--------:| 34 | | `user` | `{}` | Opsgenie User configuration | Yes | 35 | 36 | 37 | ## Outputs 38 | 39 | | Name | Description | 40 | |:----------------------------|:-----------------------------------------| 41 | | `user_id` | The ID of the Opsgenie User | 42 | | `user_name` | The name of the Opsgenie User | 43 | -------------------------------------------------------------------------------- /modules/user/main.tf: -------------------------------------------------------------------------------- 1 | resource "opsgenie_user" "this" { 2 | count = module.this.enabled ? 1 : 0 3 | 4 | username = var.user.username 5 | full_name = var.user.full_name 6 | role = var.user.role 7 | locale = try(var.user.locale, "en_US") 8 | timezone = try(var.user.timezone, "America/New_York") 9 | } 10 | -------------------------------------------------------------------------------- /modules/user/outputs.tf: -------------------------------------------------------------------------------- 1 | output "user_id" { 2 | description = "The ID of the Opsgenie User" 3 | value = try(opsgenie_user.this[0].id, null) 4 | } 5 | 6 | output "user_name" { 7 | description = "The username of the Opsgenie User" 8 | value = try(opsgenie_user.this[0].username, null) 9 | } 10 | -------------------------------------------------------------------------------- /modules/user/variables.tf: -------------------------------------------------------------------------------- 1 | variable "user" { 2 | default = {} 3 | description = "Opsgenie User configuration" 4 | } 5 | -------------------------------------------------------------------------------- /modules/user/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13.0" 3 | 4 | required_providers { 5 | opsgenie = { 6 | source = "opsgenie/opsgenie" 7 | version = ">= 0.4" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /outputs.tf: -------------------------------------------------------------------------------- 1 | output "alert_policy_id" { 2 | description = "The ID of the Opsgenie Alert Policy" 3 | value = module.alert_policy.alert_policy_id 4 | } 5 | 6 | output "alert_policy_name" { 7 | description = "Name of the Opsgenie Alert Policy" 8 | value = module.alert_policy.alert_policy_name 9 | } 10 | 11 | output "alert_policy_filter" { 12 | description = "Filters of the Opsgenie Alert Policy" 13 | value = module.alert_policy.alert_policy_filter 14 | } 15 | 16 | output "alert_policy_tags" { 17 | description = "Tags of the Opsgenie Alert Policy" 18 | value = module.alert_policy.alert_policy_tags 19 | } 20 | 21 | output "alert_policy_priority" { 22 | description = "Priority of the Opsgenie Alert Policy" 23 | value = module.alert_policy.alert_policy_priority 24 | } 25 | 26 | output "alert_policy_responders" { 27 | description = "Responders of the Opsgenie Alert Policy." 28 | value = module.alert_policy.alert_policy_responders 29 | } 30 | 31 | output "api_integration_api_key" { 32 | description = "API key of the created integration" 33 | value = module.api_integration.api_integration_api_key 34 | sensitive = true 35 | } 36 | 37 | output "api_integration_name" { 38 | description = "The name of the Opsgenie API Integration" 39 | value = module.api_integration.api_integration_name 40 | } 41 | 42 | output "api_integration_id" { 43 | description = "The ID of the Opsgenie API Integration" 44 | value = module.api_integration.api_integration_id 45 | } 46 | 47 | output "escalation_id" { 48 | description = "The ID of the Opsgenie Escalation" 49 | value = module.escalation.escalation_id 50 | } 51 | 52 | output "escalation_name" { 53 | description = "Name of the Opsgenie Escalation" 54 | value = module.escalation.escalation_name 55 | } 56 | 57 | output "integration_action_id" { 58 | description = "The ID of the Opsgenie Integration Action" 59 | value = module.integration_action.integration_action_id 60 | } 61 | 62 | output "notification_policy_id" { 63 | description = "The ID of the Opsgenie Notification Policy" 64 | value = module.notification_policy.notification_policy_id 65 | } 66 | 67 | output "notification_policy_name" { 68 | description = "The name of the Opsgenie Notification Policy" 69 | value = module.notification_policy.notification_policy_name 70 | } 71 | 72 | output "team_id" { 73 | description = "The ID of the Opsgenie Team" 74 | value = module.team.team_id 75 | } 76 | 77 | output "team_name" { 78 | description = "The name of the Opsgenie Team" 79 | value = module.team.team_name 80 | } 81 | 82 | output "team_routing_rule_id" { 83 | description = "The ID of the Opsgenie Team Routing Rule" 84 | value = module.team_routing_rule.team_routing_rule_id 85 | } 86 | 87 | output "team_routing_rule_name" { 88 | description = "The name of the Opsgenie Team Routing Rule" 89 | value = module.team_routing_rule.team_routing_rule_name 90 | } 91 | 92 | output "user_id" { 93 | description = "The ID of the Opsgenie User" 94 | value = module.user.user_id 95 | } 96 | 97 | output "user_name" { 98 | description = "The name of the Opsgenie User" 99 | value = module.user.user_name 100 | } 101 | 102 | output "service_id" { 103 | description = "The ID of the Opsgenie Service" 104 | value = module.service.service_id 105 | } 106 | 107 | output "service_name" { 108 | description = "The name of the Opsgenie Service" 109 | value = module.service.service_name 110 | } 111 | 112 | output "service_incident_rule_id" { 113 | description = "The ID of the Opsgenie Service Incident Rule" 114 | value = module.service_incident_rule.service_incident_rule_id 115 | } 116 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | .test-harness 2 | .envrc 3 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | TEST_HARNESS ?= https://github.com/cloudposse/test-harness.git 2 | TEST_HARNESS_BRANCH ?= master 3 | TEST_HARNESS_PATH = $(realpath .test-harness) 4 | BATS_ARGS ?= --tap 5 | BATS_LOG ?= test.log 6 | 7 | # Define a macro to run the tests 8 | define RUN_TESTS 9 | @echo "Running tests in $(1)" 10 | @cd $(1) && bats $(BATS_ARGS) $(addsuffix .bats,$(addprefix $(TEST_HARNESS_PATH)/test/terraform/,$(TESTS))) 11 | endef 12 | 13 | default: all 14 | 15 | -include Makefile.* 16 | 17 | ## Provision the test-harnesss 18 | .test-harness: 19 | [ -d $@ ] || git clone --depth=1 -b $(TEST_HARNESS_BRANCH) $(TEST_HARNESS) $@ 20 | 21 | ## Initialize the tests 22 | init: .test-harness 23 | 24 | ## Install all dependencies (OS specific) 25 | deps:: 26 | @exit 0 27 | 28 | ## Clean up the test harness 29 | clean: 30 | [ "$(TEST_HARNESS_PATH)" == "/" ] || rm -rf $(TEST_HARNESS_PATH) 31 | 32 | ## Run all tests 33 | all: module pre-test examples/complete examples/advanced_features examples/alert_policy examples/api_integration examples/complete examples/config examples/escalation examples/integration_action examples/notification_policy examples/schedule examples/team examples/team_routing_rule examples/user 34 | 35 | ## Run basic sanity checks against the module itself 36 | module: export TESTS ?= installed lint get-modules module-pinning get-plugins provider-pinning validate terraform-docs input-descriptions output-descriptions 37 | module: deps 38 | $(call RUN_TESTS, ../) 39 | 40 | pre-test: 41 | export TESTS ?= installed lint get-modules get-plugins validate 42 | 43 | ## Run tests against example 44 | examples/complete: deps 45 | $(call RUN_TESTS, ../$@) 46 | examples/advanced_features: deps 47 | $(call RUN_TESTS, ../$@) 48 | examples/alert_policy: deps 49 | $(call RUN_TESTS, ../$@) 50 | examples/api_integration: deps 51 | $(call RUN_TESTS, ../$@) 52 | examples/complete: deps 53 | $(call RUN_TESTS, ../$@) 54 | examples/config: deps 55 | $(call RUN_TESTS, ../$@) 56 | examples/escalation: deps 57 | $(call RUN_TESTS, ../$@) 58 | examples/integration_action: deps 59 | $(call RUN_TESTS, ../$@) 60 | examples/notification_policy: deps 61 | $(call RUN_TESTS, ../$@) 62 | examples/schedule: deps 63 | $(call RUN_TESTS, ../$@) 64 | examples/team: deps 65 | $(call RUN_TESTS, ../$@) 66 | examples/team_routing_rule: deps 67 | $(call RUN_TESTS, ../$@) 68 | examples/user: deps 69 | $(call RUN_TESTS, ../$@) 70 | -------------------------------------------------------------------------------- /test/Makefile.alpine: -------------------------------------------------------------------------------- 1 | ifneq (,$(wildcard /sbin/apk)) 2 | ## Install all dependencies for alpine 3 | deps:: init 4 | @apk add --update terraform-docs@cloudposse json2hcl@cloudposse 5 | endif 6 | -------------------------------------------------------------------------------- /test/src/.gitignore: -------------------------------------------------------------------------------- 1 | .gopath 2 | vendor/ 3 | -------------------------------------------------------------------------------- /test/src/Makefile: -------------------------------------------------------------------------------- 1 | export TF_CLI_ARGS_init ?= -get-plugins=true 2 | export TERRAFORM_VERSION ?= $(shell curl -s https://checkpoint-api.hashicorp.com/v1/check/terraform | jq -r -M '.current_version' | cut -d. -f1-2) 3 | 4 | .DEFAULT_GOAL : all 5 | 6 | .PHONY: all 7 | ## Default target 8 | all: test 9 | 10 | .PHONY : init 11 | ## Initialize tests 12 | init: 13 | @exit 0 14 | 15 | .PHONY : test 16 | ## Run tests 17 | test: init 18 | go mod download 19 | go test -v -timeout 60m -parallel 8 20 | 21 | ## Run tests in docker container 22 | docker/test: 23 | docker run --name terratest --rm -it -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_SESSION_TOKEN -e GITHUB_TOKEN \ 24 | -e PATH="/usr/local/terraform/$(TERRAFORM_VERSION)/bin:/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" \ 25 | -v $(CURDIR)/../../:/module/ cloudposse/test-harness:latest -C /module/test/src test 26 | 27 | .PHONY : clean 28 | ## Clean up files 29 | clean: 30 | rm -rf ../../examples/complete/*.tfstate* 31 | -------------------------------------------------------------------------------- /test/src/examples_advanced_features.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "github.com/gruntwork-io/terratest/modules/random" 5 | "github.com/gruntwork-io/terratest/modules/terraform" 6 | testStructure "github.com/gruntwork-io/terratest/modules/test-structure" 7 | "strings" 8 | "testing" 9 | ) 10 | 11 | // Test the Terraform module in examples/advanced_features using Terratest. 12 | func TestExamplesAdvancedFeatures(t *testing.T) { 13 | t.Parallel() 14 | randID := strings.ToLower(random.UniqueId()) 15 | attributes := []string{randID} 16 | 17 | rootFolder := "../../" 18 | terraformFolderRelativeToRoot := "examples/advanced_features" 19 | varFiles := []string{"fixtures.tfvars"} 20 | 21 | tempTestFolder := testStructure.CopyTerraformFolderToTemp(t, rootFolder, terraformFolderRelativeToRoot) 22 | 23 | terraformOptions := &terraform.Options{ 24 | // The path to where our Terraform code is located 25 | TerraformDir: tempTestFolder, 26 | Upgrade: true, 27 | // Variables to pass to our Terraform code using -var-file options 28 | VarFiles: varFiles, 29 | Vars: map[string]interface{}{ 30 | "attributes": attributes, 31 | }, 32 | } 33 | 34 | // At the end of the test, run `terraform destroy` to clean up any resources that were created 35 | defer cleanup(t, terraformOptions, tempTestFolder) 36 | 37 | // This will run `terraform init` and `terraform apply` and fail the test if there are any errors 38 | terraform.InitAndApply(t, terraformOptions) 39 | } 40 | -------------------------------------------------------------------------------- /test/src/examples_alert_policy_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "github.com/gruntwork-io/terratest/modules/random" 5 | "github.com/gruntwork-io/terratest/modules/terraform" 6 | testStructure "github.com/gruntwork-io/terratest/modules/test-structure" 7 | "github.com/stretchr/testify/assert" 8 | "strings" 9 | "testing" 10 | ) 11 | 12 | // Test the Terraform module in examples/alert_policy using Terratest. 13 | func TestExamplesAlertPolicy(t *testing.T) { 14 | t.SkipNow() 15 | // We are skipping this test because of the following error: 16 | // Error: Error occurred with Status code: 403, Message: You are not authorized to use policies!, Took: 0.001000, RequestId: 66e46694-8e4c-4e20-9644-178db4b2f4c1 17 | 18 | t.Parallel() 19 | randID := strings.ToLower(random.UniqueId()) 20 | attributes := []string{randID} 21 | 22 | rootFolder := "../../" 23 | terraformFolderRelativeToRoot := "examples/alert_policy" 24 | varFiles := []string{"fixtures.tfvars"} 25 | 26 | tempTestFolder := testStructure.CopyTerraformFolderToTemp(t, rootFolder, terraformFolderRelativeToRoot) 27 | 28 | terraformOptions := &terraform.Options{ 29 | // The path to where our Terraform code is located 30 | TerraformDir: tempTestFolder, 31 | Upgrade: true, 32 | // Variables to pass to our Terraform code using -var-file options 33 | VarFiles: varFiles, 34 | Vars: map[string]interface{}{ 35 | "attributes": attributes, 36 | }, 37 | } 38 | 39 | // At the end of the test, run `terraform destroy` to clean up any resources that were created 40 | defer cleanup(t, terraformOptions, tempTestFolder) 41 | 42 | // This will run `terraform init` and `terraform apply` and fail the test if there are any errors 43 | terraform.InitAndApply(t, terraformOptions) 44 | 45 | // Run `terraform output` to get the value of an output variable and test it 46 | outputAlertPolicyName := terraform.Output(t, terraformOptions, "alert_policy_name") 47 | assert.Equal(t, "eg-test-alert-policy", outputAlertPolicyName) 48 | 49 | outputAlertPolicyPriority := terraform.Output(t, terraformOptions, "alert_policy_priority") 50 | assert.Equal(t, "P1", outputAlertPolicyPriority) 51 | 52 | expectedAlertPolicyTags := `[ 53 | "test1", 54 | "test2", 55 | ]` 56 | outputAlertPolicyTags := terraform.Output(t, terraformOptions, "alert_policy_tags") 57 | assert.Equal(t, expectedAlertPolicyTags, outputAlertPolicyTags) 58 | 59 | expectedAlertPolicyFilter := `[ 60 | { 61 | "conditions" = [ 62 | { 63 | "expected_value" = ".*prod.*" 64 | "field" = "source" 65 | "key" = "" 66 | "not" = false 67 | "operation" = "matches" 68 | "order" = 0 69 | }, 70 | { 71 | "expected_value" = "severity:critical" 72 | "field" = "tags" 73 | "key" = "" 74 | "not" = false 75 | "operation" = "contains" 76 | "order" = 0 77 | }, 78 | ] 79 | "type" = "match-all-conditions" 80 | }, 81 | ]` 82 | outputAlertPolicyFilter := terraform.Output(t, terraformOptions, "alert_policy_filter") 83 | assert.Equal(t, expectedAlertPolicyFilter, outputAlertPolicyFilter) 84 | 85 | expectedAlertPolicyResponders := `[ 86 | { 87 | "id" = .* 88 | "name" = "" 89 | "type" = "team" 90 | "username" = "" 91 | }, 92 | ]` 93 | outputAlertPolicyResponders := terraform.Output(t, terraformOptions, "alert_policy_responders") 94 | assert.Regexp(t, expectedAlertPolicyResponders, outputAlertPolicyResponders) 95 | } 96 | -------------------------------------------------------------------------------- /test/src/examples_api_integration_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "github.com/gruntwork-io/terratest/modules/random" 5 | "github.com/gruntwork-io/terratest/modules/terraform" 6 | testStructure "github.com/gruntwork-io/terratest/modules/test-structure" 7 | "github.com/stretchr/testify/assert" 8 | "strings" 9 | "testing" 10 | ) 11 | 12 | // Test the Terraform module in examples/api_integration using Terratest. 13 | func TestExamplesApiIntegration(t *testing.T) { 14 | t.Parallel() 15 | randID := strings.ToLower(random.UniqueId()) 16 | attributes := []string{randID} 17 | 18 | rootFolder := "../../" 19 | terraformFolderRelativeToRoot := "examples/api_integration" 20 | varFiles := []string{"fixtures.tfvars"} 21 | 22 | tempTestFolder := testStructure.CopyTerraformFolderToTemp(t, rootFolder, terraformFolderRelativeToRoot) 23 | 24 | terraformOptions := &terraform.Options{ 25 | // The path to where our Terraform code is located 26 | TerraformDir: tempTestFolder, 27 | Upgrade: true, 28 | // Variables to pass to our Terraform code using -var-file options 29 | VarFiles: varFiles, 30 | Vars: map[string]interface{}{ 31 | "attributes": attributes, 32 | }, 33 | } 34 | 35 | // At the end of the test, run `terraform destroy` to clean up any resources that were created 36 | defer cleanup(t, terraformOptions, tempTestFolder) 37 | 38 | // This will run `terraform init` and `terraform apply` and fail the test if there are any errors 39 | terraform.InitAndApply(t, terraformOptions) 40 | 41 | // Run `terraform output` to get the value of an output variable 42 | outputApiIntegrationName := terraform.Output(t, terraformOptions, "api_integration_name") 43 | expectedApiIntegrationName := "eg-test-api-integration-" + randID 44 | 45 | // Verify we're getting back the outputs we expect 46 | assert.Equal(t, expectedApiIntegrationName, outputApiIntegrationName) 47 | } 48 | -------------------------------------------------------------------------------- /test/src/examples_complete_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "regexp" 5 | "strings" 6 | "testing" 7 | 8 | "github.com/gruntwork-io/terratest/modules/random" 9 | "github.com/gruntwork-io/terratest/modules/terraform" 10 | testStructure "github.com/gruntwork-io/terratest/modules/test-structure" 11 | "github.com/stretchr/testify/assert" 12 | ) 13 | 14 | // Test the Terraform module in examples/complete using Terratest. 15 | func TestExamplesComplete(t *testing.T) { 16 | t.Parallel() 17 | randID := strings.ToLower(random.UniqueId()) 18 | attributes := []string{randID} 19 | 20 | rootFolder := "../../" 21 | terraformFolderRelativeToRoot := "examples/complete" 22 | varFiles := []string{"fixtures.tfvars"} 23 | 24 | tempTestFolder := testStructure.CopyTerraformFolderToTemp(t, rootFolder, terraformFolderRelativeToRoot) 25 | 26 | terraformOptions := &terraform.Options{ 27 | // The path to where our Terraform code is located 28 | TerraformDir: tempTestFolder, 29 | Upgrade: true, 30 | // Variables to pass to our Terraform code using -var-file options 31 | VarFiles: varFiles, 32 | Vars: map[string]interface{}{ 33 | "attributes": attributes, 34 | }, 35 | } 36 | 37 | // At the end of the test, run `terraform destroy` to clean up any resources that were created 38 | defer cleanup(t, terraformOptions, tempTestFolder) 39 | 40 | // This will run `terraform init` and `terraform apply` and fail the test if there are any errors 41 | terraform.InitAndApply(t, terraformOptions) 42 | 43 | // Run `terraform output` to get the value of an output variable 44 | outputApiIntegrationName := terraform.Output(t, terraformOptions, "api_integration_name") 45 | 46 | // Verify we're getting back the outputs we expect 47 | expectedWorkflowName := "eg-test-incident-management-workflow-" + randID 48 | assert.Equal(t, expectedWorkflowName, outputApiIntegrationName) 49 | 50 | // Run `terraform output` to get the value of an output variable 51 | 52 | outputEscalationName := terraform.Output(t, terraformOptions, "escalation_name") 53 | expectedEscalationName := "eg-test-incident-management-workflow-" + randID + "-escalation" 54 | 55 | // Verify we're getting back the outputs we expect 56 | assert.Equal(t, expectedEscalationName, outputEscalationName) 57 | 58 | // Run `terraform output` to get the value of an output variable 59 | outputTeamRoutingRuleName := terraform.Output(t, terraformOptions, "team_routing_rule_name") 60 | expectedTeamRoutingRuleName := "eg-test-incident-management-workflow-" + randID 61 | 62 | // Verify we're getting back the outputs we expect 63 | assert.Equal(t, expectedTeamRoutingRuleName, outputTeamRoutingRuleName) 64 | 65 | // Run `terraform output` to get the value of an output variable 66 | outputTeamName := terraform.Output(t, terraformOptions, "team_name") 67 | expectedTeamName := "eg-test-incident-management-workflow-" + randID 68 | // Verify we're getting back the outputs we expect 69 | assert.Equal(t, expectedTeamName, outputTeamName) 70 | } 71 | 72 | func TestExamplesCompleteDisabled(t *testing.T) { 73 | t.Parallel() 74 | randID := strings.ToLower(random.UniqueId()) 75 | attributes := []string{randID} 76 | 77 | rootFolder := "../../" 78 | terraformFolderRelativeToRoot := "examples/complete" 79 | varFiles := []string{"fixtures.tfvars"} 80 | 81 | tempTestFolder := testStructure.CopyTerraformFolderToTemp(t, rootFolder, terraformFolderRelativeToRoot) 82 | 83 | terraformOptions := &terraform.Options{ 84 | // The path to where our Terraform code is located 85 | TerraformDir: tempTestFolder, 86 | Upgrade: true, 87 | // Variables to pass to our Terraform code using -var-file options 88 | VarFiles: varFiles, 89 | Vars: map[string]interface{}{ 90 | "attributes": attributes, 91 | "enabled": false, 92 | }, 93 | } 94 | 95 | // At the end of the test, run `terraform destroy` to clean up any resources that were created 96 | defer cleanup(t, terraformOptions, tempTestFolder) 97 | 98 | // This will run `terraform init` and `terraform apply` and fail the test if there are any errors 99 | results := terraform.InitAndApply(t, terraformOptions) 100 | 101 | // Should complete successfully without creating or changing any resources. 102 | // Extract the "Resources:" section of the output to make the error message more readable. 103 | re := regexp.MustCompile(`Resources: [^.]+\.`) 104 | match := re.FindString(results) 105 | assert.Equal(t, "Resources: 0 added, 0 changed, 0 destroyed.", match, "Re-applying the same configuration should not change any resources") 106 | } 107 | -------------------------------------------------------------------------------- /test/src/examples_config_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "github.com/gruntwork-io/terratest/modules/random" 5 | "github.com/gruntwork-io/terratest/modules/terraform" 6 | testStructure "github.com/gruntwork-io/terratest/modules/test-structure" 7 | "strings" 8 | "testing" 9 | ) 10 | 11 | // Test the Terraform module in examples/config using Terratest. 12 | func TestExamplesConfig(t *testing.T) { 13 | // We skip the ExamplesConfig Test because our API key doesn't allow full testing of the modules used in the example. 14 | t.SkipNow() 15 | 16 | t.Parallel() 17 | randID := strings.ToLower(random.UniqueId()) 18 | attributes := []string{randID} 19 | 20 | rootFolder := "../../" 21 | terraformFolderRelativeToRoot := "examples/config" 22 | varFiles := []string{"fixtures.tfvars"} 23 | 24 | tempTestFolder := testStructure.CopyTerraformFolderToTemp(t, rootFolder, terraformFolderRelativeToRoot) 25 | 26 | terraformOptions := &terraform.Options{ 27 | // The path to where our Terraform code is located 28 | TerraformDir: tempTestFolder, 29 | Upgrade: true, 30 | // Variables to pass to our Terraform code using -var-file options 31 | VarFiles: varFiles, 32 | Vars: map[string]interface{}{ 33 | "attributes": attributes, 34 | }, 35 | } 36 | 37 | // At the end of the test, run `terraform destroy` to clean up any resources that were created 38 | defer cleanup(t, terraformOptions, tempTestFolder) 39 | 40 | // This will run `terraform init` and `terraform apply` and fail the test if there are any errors 41 | terraform.InitAndApply(t, terraformOptions) 42 | } 43 | -------------------------------------------------------------------------------- /test/src/examples_escalation_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "github.com/gruntwork-io/terratest/modules/random" 5 | "github.com/gruntwork-io/terratest/modules/terraform" 6 | testStructure "github.com/gruntwork-io/terratest/modules/test-structure" 7 | "github.com/stretchr/testify/assert" 8 | "strings" 9 | "testing" 10 | ) 11 | 12 | // Test the Terraform module in examples/escalation using Terratest. 13 | func TestExamplesEscalation(t *testing.T) { 14 | t.Parallel() 15 | randID := strings.ToLower(random.UniqueId()) 16 | attributes := []string{randID} 17 | 18 | rootFolder := "../../" 19 | terraformFolderRelativeToRoot := "examples/escalation" 20 | varFiles := []string{"fixtures.tfvars"} 21 | 22 | tempTestFolder := testStructure.CopyTerraformFolderToTemp(t, rootFolder, terraformFolderRelativeToRoot) 23 | 24 | terraformOptions := &terraform.Options{ 25 | // The path to where our Terraform code is located 26 | TerraformDir: tempTestFolder, 27 | Upgrade: true, 28 | // Variables to pass to our Terraform code using -var-file options 29 | VarFiles: varFiles, 30 | Vars: map[string]interface{}{ 31 | "attributes": attributes, 32 | }, 33 | } 34 | 35 | // At the end of the test, run `terraform destroy` to clean up any resources that were created 36 | defer cleanup(t, terraformOptions, tempTestFolder) 37 | 38 | // This will run `terraform init` and `terraform apply` and fail the test if there are any errors 39 | terraform.InitAndApply(t, terraformOptions) 40 | 41 | // Run `terraform output` to get the value of an output variable 42 | outputEscalationName := terraform.Output(t, terraformOptions, "escalation_name") 43 | expectedEscalationName := "eg-test-escalation-" + randID 44 | // Verify we're getting back the outputs we expect 45 | assert.Equal(t, expectedEscalationName, outputEscalationName) 46 | } 47 | -------------------------------------------------------------------------------- /test/src/examples_integration_action.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "github.com/gruntwork-io/terratest/modules/random" 5 | "github.com/gruntwork-io/terratest/modules/terraform" 6 | testStructure "github.com/gruntwork-io/terratest/modules/test-structure" 7 | "strings" 8 | "testing" 9 | ) 10 | 11 | // Test the Terraform module in examples/integration_action using Terratest. 12 | func TestExamplesIntegrationAction(t *testing.T) { 13 | t.Parallel() 14 | randID := strings.ToLower(random.UniqueId()) 15 | attributes := []string{randID} 16 | 17 | rootFolder := "../../" 18 | terraformFolderRelativeToRoot := "examples/integration_action" 19 | varFiles := []string{"fixtures.tfvars"} 20 | 21 | tempTestFolder := testStructure.CopyTerraformFolderToTemp(t, rootFolder, terraformFolderRelativeToRoot) 22 | 23 | terraformOptions := &terraform.Options{ 24 | // The path to where our Terraform code is located 25 | TerraformDir: tempTestFolder, 26 | Upgrade: true, 27 | // Variables to pass to our Terraform code using -var-file options 28 | VarFiles: varFiles, 29 | Vars: map[string]interface{}{ 30 | "attributes": attributes, 31 | }, 32 | } 33 | 34 | // At the end of the test, run `terraform destroy` to clean up any resources that were created 35 | defer cleanup(t, terraformOptions, tempTestFolder) 36 | 37 | // This will run `terraform init` and `terraform apply` and fail the test if there are any errors 38 | terraform.InitAndApply(t, terraformOptions) 39 | } 40 | -------------------------------------------------------------------------------- /test/src/examples_notification_policy_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "github.com/gruntwork-io/terratest/modules/random" 5 | "github.com/gruntwork-io/terratest/modules/terraform" 6 | testStructure "github.com/gruntwork-io/terratest/modules/test-structure" 7 | "github.com/stretchr/testify/assert" 8 | "strings" 9 | "testing" 10 | ) 11 | 12 | // Test the Terraform module in examples/notification_policy using Terratest. 13 | func TestExamplesNotificationPolicyDeDuplicationAction(t *testing.T) { 14 | // We are skipping this test because of the following error: 15 | // Error: Error occurred with Status code: 403, Message: You are not authorized to use policies!, Took: 0.001000, RequestId: 66e46694-8e4c-4e20-9644-178db4b2f4c1 16 | t.SkipNow() 17 | 18 | t.Parallel() 19 | randID := strings.ToLower(random.UniqueId()) 20 | attributes := []string{randID} 21 | 22 | rootFolder := "../../" 23 | terraformFolderRelativeToRoot := "examples/notification_policy" 24 | varFiles := []string{"fixtures.de_duplication_action.tfvars"} 25 | 26 | tempTestFolder := testStructure.CopyTerraformFolderToTemp(t, rootFolder, terraformFolderRelativeToRoot) 27 | 28 | terraformOptions := &terraform.Options{ 29 | // The path to where our Terraform code is located 30 | TerraformDir: tempTestFolder, 31 | Upgrade: true, 32 | // Variables to pass to our Terraform code using -var-file options 33 | VarFiles: varFiles, 34 | Vars: map[string]interface{}{ 35 | "attributes": attributes, 36 | }, 37 | } 38 | 39 | // At the end of the test, run `terraform destroy` to clean up any resources that were created 40 | defer cleanup(t, terraformOptions, tempTestFolder) 41 | 42 | // This will run `terraform init` and `terraform apply` and fail the test if there are any errors 43 | terraform.InitAndApply(t, terraformOptions) 44 | 45 | // Run `terraform output` to get the value of an output variable 46 | outputNotificationPolicyName := terraform.Output(t, terraformOptions, "notification_policy_name") 47 | 48 | // Verify we're getting back the outputs we expect 49 | assert.Regexp(t, "^eg-test-notification-policy$", outputNotificationPolicyName) 50 | } 51 | 52 | func TestExamplesNotificationPolicyDelayAction(t *testing.T) { 53 | // We are skipping this test because of the following error: 54 | // Error: Error occurred with Status code: 403, Message: You are not authorized to use policies!, Took: 0.001000, RequestId: 66e46694-8e4c-4e20-9644-178db4b2f4c1 55 | t.SkipNow() 56 | 57 | t.Parallel() 58 | randID := strings.ToLower(random.UniqueId()) 59 | attributes := []string{randID} 60 | 61 | rootFolder := "../../" 62 | terraformFolderRelativeToRoot := "examples/notification_policy" 63 | varFiles := []string{"fixtures.delay_action.tfvars"} 64 | 65 | tempTestFolder := testStructure.CopyTerraformFolderToTemp(t, rootFolder, terraformFolderRelativeToRoot) 66 | 67 | terraformOptions := &terraform.Options{ 68 | // The path to where our Terraform code is located 69 | TerraformDir: tempTestFolder, 70 | Upgrade: true, 71 | // Variables to pass to our Terraform code using -var-file options 72 | VarFiles: varFiles, 73 | Vars: map[string]interface{}{ 74 | "attributes": attributes, 75 | }, 76 | } 77 | 78 | // At the end of the test, run `terraform destroy` to clean up any resources that were created 79 | defer cleanup(t, terraformOptions, tempTestFolder) 80 | 81 | // This will run `terraform init` and `terraform apply` and fail the test if there are any errors 82 | terraform.InitAndApply(t, terraformOptions) 83 | 84 | // Run `terraform output` to get the value of an output variable 85 | outputNotificationPolicyName := terraform.Output(t, terraformOptions, "notification_policy_name") 86 | 87 | // Verify we're getting back the outputs we expect 88 | assert.Regexp(t, "^eg-test-notification-policy$", outputNotificationPolicyName) 89 | } 90 | -------------------------------------------------------------------------------- /test/src/examples_team_routing_rule_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "github.com/gruntwork-io/terratest/modules/random" 5 | "github.com/gruntwork-io/terratest/modules/terraform" 6 | testStructure "github.com/gruntwork-io/terratest/modules/test-structure" 7 | "github.com/stretchr/testify/assert" 8 | "strings" 9 | "testing" 10 | ) 11 | 12 | // Test the Terraform module in examples/team_routing_rule using Terratest. 13 | func TestExamplesTeamRoutingRule(t *testing.T) { 14 | t.Parallel() 15 | randID := strings.ToLower(random.UniqueId()) 16 | attributes := []string{randID} 17 | 18 | rootFolder := "../../" 19 | terraformFolderRelativeToRoot := "examples/team_routing_rule" 20 | varFiles := []string{"fixtures.tfvars"} 21 | 22 | tempTestFolder := testStructure.CopyTerraformFolderToTemp(t, rootFolder, terraformFolderRelativeToRoot) 23 | 24 | terraformOptions := &terraform.Options{ 25 | // The path to where our Terraform code is located 26 | TerraformDir: tempTestFolder, 27 | Upgrade: true, 28 | // Variables to pass to our Terraform code using -var-file options 29 | VarFiles: varFiles, 30 | Vars: map[string]interface{}{ 31 | "attributes": attributes, 32 | }, 33 | } 34 | 35 | // At the end of the test, run `terraform destroy` to clean up any resources that were created 36 | defer cleanup(t, terraformOptions, tempTestFolder) 37 | 38 | // This will run `terraform init` and `terraform apply` and fail the test if there are any errors 39 | terraform.InitAndApply(t, terraformOptions) 40 | 41 | // Run `terraform output` to get the value of an output variable 42 | outputTeamRoutingRuleName := terraform.Output(t, terraformOptions, "team_routing_rule_name") 43 | expectedTeamRoutingRuleName := "eg-test-team-routing-rule-" + randID 44 | // Verify we're getting back the outputs we expect 45 | assert.Equal(t, expectedTeamRoutingRuleName, outputTeamRoutingRuleName) 46 | } 47 | -------------------------------------------------------------------------------- /test/src/examples_team_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "github.com/gruntwork-io/terratest/modules/random" 5 | "github.com/gruntwork-io/terratest/modules/terraform" 6 | testStructure "github.com/gruntwork-io/terratest/modules/test-structure" 7 | "github.com/stretchr/testify/assert" 8 | "strings" 9 | "testing" 10 | ) 11 | 12 | // Test the Terraform module in examples/team using Terratest. 13 | func TestExamplesTeam(t *testing.T) { 14 | t.Parallel() 15 | randID := strings.ToLower(random.UniqueId()) 16 | attributes := []string{randID} 17 | 18 | rootFolder := "../../" 19 | terraformFolderRelativeToRoot := "examples/team" 20 | varFiles := []string{"fixtures.tfvars"} 21 | 22 | tempTestFolder := testStructure.CopyTerraformFolderToTemp(t, rootFolder, terraformFolderRelativeToRoot) 23 | 24 | terraformOptions := &terraform.Options{ 25 | // The path to where our Terraform code is located 26 | TerraformDir: tempTestFolder, 27 | Upgrade: true, 28 | // Variables to pass to our Terraform code using -var-file options 29 | VarFiles: varFiles, 30 | Vars: map[string]interface{}{ 31 | "attributes": attributes, 32 | }, 33 | } 34 | 35 | // At the end of the test, run `terraform destroy` to clean up any resources that were created 36 | defer cleanup(t, terraformOptions, tempTestFolder) 37 | 38 | // This will run `terraform init` and `terraform apply` and fail the test if there are any errors 39 | terraform.InitAndApply(t, terraformOptions) 40 | 41 | // Run `terraform output` to get the value of an output variable 42 | outputTeamName := terraform.Output(t, terraformOptions, "team_name") 43 | expectedTeamName := "eg-test-team-" + randID 44 | // Verify we're getting back the outputs we expect 45 | 46 | assert.Equal(t, expectedTeamName, outputTeamName) 47 | } 48 | -------------------------------------------------------------------------------- /test/src/examples_user_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "github.com/gruntwork-io/terratest/modules/random" 5 | "github.com/gruntwork-io/terratest/modules/terraform" 6 | testStructure "github.com/gruntwork-io/terratest/modules/test-structure" 7 | "github.com/stretchr/testify/assert" 8 | "strings" 9 | "testing" 10 | ) 11 | 12 | // Test the Terraform module in examples/user using Terratest. 13 | func TestExamplesUser(t *testing.T) { 14 | t.Parallel() 15 | randID := strings.ToLower(random.UniqueId()) 16 | attributes := []string{randID} 17 | 18 | rootFolder := "../../" 19 | terraformFolderRelativeToRoot := "examples/user" 20 | varFiles := []string{"fixtures.tfvars"} 21 | 22 | tempTestFolder := testStructure.CopyTerraformFolderToTemp(t, rootFolder, terraformFolderRelativeToRoot) 23 | 24 | terraformOptions := &terraform.Options{ 25 | // The path to where our Terraform code is located 26 | TerraformDir: tempTestFolder, 27 | Upgrade: true, 28 | // Variables to pass to our Terraform code using -var-file options 29 | VarFiles: varFiles, 30 | Vars: map[string]interface{}{ 31 | "attributes": attributes, 32 | "random_string": randID, 33 | }, 34 | } 35 | 36 | // At the end of the test, run `terraform destroy` to clean up any resources that were created 37 | defer cleanup(t, terraformOptions, tempTestFolder) 38 | 39 | // This will run `terraform init` and `terraform apply` and fail the test if there are any errors 40 | terraform.InitAndApply(t, terraformOptions) 41 | 42 | // Run `terraform output` to get the value of an output variable 43 | userId := terraform.Output(t, terraformOptions, "user_id") 44 | 45 | // Verify we're getting back the outputs we expect 46 | assert.NotEmpty(t, userId) 47 | } 48 | -------------------------------------------------------------------------------- /test/src/utils.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/gruntwork-io/terratest/modules/terraform" 8 | ) 9 | 10 | func cleanup(t *testing.T, terraformOptions *terraform.Options, tempTestFolder string) { 11 | terraform.Destroy(t, terraformOptions) 12 | _ = os.RemoveAll(tempTestFolder) 13 | } 14 | -------------------------------------------------------------------------------- /variables.tf: -------------------------------------------------------------------------------- 1 | variable "opsgenie_provider_api_key" { 2 | type = string 3 | description = "The API Key for the Opsgenie Integration. If omitted, the OPSGENIE_API_KEY environment variable is used" 4 | default = "" 5 | } 6 | 7 | variable "alert_policy" { 8 | default = {} 9 | description = "Opsgenie Alert Policy configuration" 10 | } 11 | 12 | variable "api_integration" { 13 | type = map(any) 14 | default = {} 15 | description = "Opsgenie API Integration configuration" 16 | } 17 | 18 | variable "escalation" { 19 | default = {} 20 | description = "Opsgenie Escalation configuration" 21 | } 22 | 23 | variable "integration_action" { 24 | default = {} 25 | description = "Opsgenie Integration Action configuration" 26 | } 27 | 28 | variable "notification_policy" { 29 | default = {} 30 | description = "Opsgenie Notification Policy configuration" 31 | } 32 | 33 | variable "team" { 34 | default = {} 35 | description = "Opsgenie Team configuration" 36 | } 37 | 38 | variable "team_routing_rule" { 39 | default = {} 40 | description = "Opsgenie Team Routing Rule configuration" 41 | } 42 | 43 | variable "user" { 44 | default = {} 45 | description = "Opsgenie User configuration" 46 | } 47 | 48 | variable "service" { 49 | default = {} 50 | description = "Opsgenie Service configuration" 51 | } 52 | 53 | variable "service_incident_rule" { 54 | default = {} 55 | description = "Opsgenie Service Incident Rule configuration" 56 | } 57 | -------------------------------------------------------------------------------- /versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13.0" 3 | 4 | required_providers { 5 | opsgenie = { 6 | source = "opsgenie/opsgenie" 7 | version = ">= 0.4" 8 | } 9 | } 10 | } 11 | --------------------------------------------------------------------------------