├── .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
├── banner.png
├── dependabot.yml
├── mergify.yml
├── renovate.json
├── settings.yml
└── workflows
│ ├── branch.yml
│ ├── chatops.yml
│ ├── release.yml
│ └── scheduled.yml
├── .gitignore
├── LICENSE
├── README.md
├── README.yaml
├── atmos.yaml
├── catalog
├── monitors
│ ├── amq.yaml
│ ├── aurora.yaml
│ ├── ec2.yaml
│ ├── host.yaml
│ ├── k8s.yaml
│ ├── rabbitmq.yaml
│ ├── rds.yaml
│ └── redshift.yaml
└── roles
│ ├── admin.yaml
│ ├── api.yaml
│ ├── apm.yaml
│ ├── billing.yaml
│ ├── dashboards.yaml
│ ├── data.yaml
│ ├── incident.yaml
│ ├── integrations.yaml
│ ├── logs.yaml
│ ├── metric.yaml
│ ├── monitors.yaml
│ ├── org.yaml
│ ├── rum.yaml
│ ├── security.yaml
│ ├── standard.yaml
│ ├── synthetics.yaml
│ ├── usage.yaml
│ └── user.yaml
├── context.tf
├── examples
├── child_organization
│ ├── context.tf
│ ├── fixtures.us-east-2.tfvars
│ ├── main.tf
│ ├── outputs.tf
│ ├── providers.tf
│ ├── variables.tf
│ └── versions.tf
├── complete
│ ├── context.tf
│ ├── fixtures.us-east-2.tfvars
│ ├── main.tf
│ ├── monitors-test
│ │ ├── anomaly-recovery-legacy-test.yaml
│ │ ├── anomaly-recovery-test.json
│ │ ├── monitor-variables-test.json
│ │ ├── schedule-legacy-test.yaml
│ │ └── schedule-test.json
│ ├── outputs.tf
│ ├── providers.tf
│ ├── variables.tf
│ └── versions.tf
├── organization_settings
│ ├── context.tf
│ ├── fixtures.us-east-2.tfvars
│ ├── main.tf
│ ├── outputs.tf
│ ├── providers.tf
│ ├── variables.tf
│ └── versions.tf
├── rbac
│ ├── context.tf
│ ├── fixtures.us-east-2.tfvars
│ ├── main.tf
│ ├── outputs.tf
│ ├── providers.tf
│ ├── variables.tf
│ └── versions.tf
├── slo
│ ├── catalog
│ │ ├── metric_slo.yaml
│ │ └── monitor_slo.yaml
│ ├── context.tf
│ ├── fixtures.us-east-2.tfvars
│ ├── main.tf
│ ├── outputs.tf
│ ├── providers.tf
│ ├── variables.tf
│ └── versions.tf
└── synthetics
│ ├── catalog
│ ├── api-schema
│ │ ├── api-multistep-test.yaml
│ │ └── browser-multistep-test.yaml
│ └── terraform-schema
│ │ ├── http.yaml
│ │ └── ssl.yaml
│ ├── context.tf
│ ├── fixtures.us-east-2.tfvars
│ ├── main.tf
│ ├── outputs.tf
│ ├── providers.tf
│ ├── variables.tf
│ └── versions.tf
├── main.tf
├── modules
├── child_organization
│ ├── context.tf
│ ├── main.tf
│ ├── outputs.tf
│ ├── variables.tf
│ └── versions.tf
├── monitors
│ ├── README.md
│ ├── context.tf
│ ├── main.tf
│ ├── normalize-legacy.tf
│ ├── outputs.tf
│ ├── variables.tf
│ └── versions.tf
├── organization_settings
│ ├── context.tf
│ ├── main.tf
│ ├── outputs.tf
│ ├── variables.tf
│ └── versions.tf
├── permissions
│ ├── context.tf
│ ├── datadog-permissions.md
│ ├── main.tf
│ ├── outputs.tf
│ └── versions.tf
├── roles
│ ├── context.tf
│ ├── main.tf
│ ├── outputs.tf
│ ├── variables.tf
│ └── versions.tf
├── slo
│ ├── README.md
│ ├── context.tf
│ ├── main.tf
│ ├── metric_slo.tf
│ ├── monitor_slo.tf
│ ├── outputs.tf
│ ├── variables.tf
│ └── versions.tf
└── synthetics
│ ├── README.md
│ ├── context.tf
│ ├── main.tf
│ ├── outputs.tf
│ ├── variables.tf
│ └── versions.tf
├── outputs.tf
├── test
├── .gitignore
├── Makefile
├── Makefile.alpine
└── src
│ ├── .gitignore
│ ├── Makefile
│ ├── examples_child_organization_test.go
│ ├── examples_complete_test.go
│ ├── examples_synthetics_test.go
│ ├── go.mod
│ └── go.sum
├── 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 = 4
21 | indent_style = tab
22 | indent_size = tab
23 |
24 | # Enforce `go` formatting rules
25 | [*.go]
26 | indent_size = unset
27 | indent_style = tab
28 |
29 | [COMMIT_EDITMSG]
30 | max_line_length = 0
31 |
--------------------------------------------------------------------------------
/.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 | [](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 | [](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 | [](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 | [](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-datadog-platform/0af3588dc7748101bc432866a5819dcf011461b1/.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/banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudposse/terraform-datadog-platform/0af3588dc7748101bc432866a5819dcf011461b1/.github/banner.png
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # Please see the documentation for all configuration options:
2 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
3 |
4 | version: 2
5 | updates:
6 | - package-ecosystem: gomod
7 | directory: /
8 | labels:
9 | - dependencies
10 | - go
11 | - no-release
12 | schedule:
13 | interval: weekly
14 | day: sunday
15 | ignore:
16 | - dependency-name: "*"
17 | update-types: ["version-update:semver-major"]
18 |
19 |
--------------------------------------------------------------------------------
/.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-datadog-platform
5 | description: Terraform module to configure and provision Datadog monitors, custom RBAC roles with permissions, Datadog synthetic tests, Datadog child organizations, and other Datadog resources from a YAML configuration, complete with automated tests.
6 | homepage: https://cloudposse.com/accelerate
7 | topics: terraform, terraform-modules, datadog, monitoring, terratest, synthetics
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 | # Compiled files
2 | *.tfstate
3 | *.tfstate.backup
4 |
5 | # Module directory
6 | .terraform/
7 | .idea
8 | *.iml
9 |
10 | .build-harness
11 | build-harness
12 | **/.terraform.lock.hcl
13 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/catalog/monitors/amq.yaml:
--------------------------------------------------------------------------------
1 | # The official Datadog API documentation with available query parameters & alert types:
2 | # https://docs.datadoghq.com/api/v1/monitors/#create-a-monitor
3 |
4 | amq-cpu-utilization:
5 | name: "(AMQ) CPU Utilization above 90%"
6 | type: metric alert
7 | query: |
8 | avg(last_15m):avg:aws.amazonmq.cpu_utilization{*} by {broker} > 90
9 | message: |
10 | {{#is_warning}}
11 | ({broker}) - CPU Utilization above 85%
12 | {{/is_warning}}
13 | {{#is_alert}}
14 | ({broker}) - CPU Utilization above 90%
15 | {{/is_alert}}
16 | escalation_message: ""
17 | tags:
18 | ManagedBy: Terraform
19 | priority: 3
20 | notify_no_data: false
21 | notify_audit: true
22 | require_full_window: true
23 | enable_logs_sample: false
24 | force_delete: true
25 | include_tags: true
26 | locked: false
27 | renotify_interval: 60
28 | timeout_h: 0
29 | evaluation_delay: 60
30 | new_host_delay: 300
31 | new_group_delay: 0
32 | groupby_simple_monitor: false
33 | renotify_occurrences: 0
34 | renotify_statuses: []
35 | validate: true
36 | no_data_timeframe: 10
37 | threshold_windows: { }
38 | thresholds:
39 | critical: 90
40 | warning: 85
41 | #unknown:
42 | #ok:
43 | #critical_recovery:
44 | #warning_recovery:
45 |
46 | amq-heap-usage:
47 | name: "(AMQ) JVM heap usage above 95%"
48 | type: metric alert
49 | query: |
50 | avg(last_15m):avg:aws.amazonmq.heap_usage{*} by {broker} > 95
51 | message: |
52 | {{#is_warning}}
53 | ({broker}) - JVM heap usage above 90%
54 | {{/is_warning}}
55 | {{#is_alert}}
56 | ({broker}) - JVM heap usage above 95%
57 | {{/is_alert}}
58 | escalation_message: ""
59 | tags:
60 | ManagedBy: Terraform
61 | priority: 3
62 | notify_no_data: false
63 | notify_audit: true
64 | require_full_window: true
65 | enable_logs_sample: false
66 | force_delete: true
67 | include_tags: true
68 | locked: false
69 | renotify_interval: 60
70 | timeout_h: 0
71 | evaluation_delay: 60
72 | new_host_delay: 300
73 | new_group_delay: 0
74 | groupby_simple_monitor: false
75 | renotify_occurrences: 0
76 | renotify_statuses: []
77 | validate: true
78 | no_data_timeframe: 10
79 | threshold_windows: { }
80 | thresholds:
81 | critical: 95
82 | warning: 90
83 | #unknown:
84 | #ok:
85 | #critical_recovery:
86 | #warning_recovery:
87 |
88 | amq-network-in:
89 | name: "(AMQ) Anomaly of a large variance in network-in bytes"
90 | type: metric alert
91 | query: |
92 | avg(last_4h):anomalies(avg:aws.amazonmq.network_in{*} by {broker}, 'agile', 2, direction='both', alert_window='last_15m', interval=60, count_default_zero='true', seasonality='hourly') >= 1
93 | message: |
94 | {{#is_alert}}
95 | ({broker}) - Anomaly of a large variance in network-in bytes
96 | {{/is_alert}}
97 | escalation_message: ""
98 | tags:
99 | ManagedBy: Terraform
100 | priority: 3
101 | notify_no_data: false
102 | notify_audit: true
103 | require_full_window: true
104 | enable_logs_sample: false
105 | force_delete: true
106 | include_tags: true
107 | locked: false
108 | renotify_interval: 60
109 | timeout_h: 0
110 | evaluation_delay: 900
111 | new_host_delay: 300
112 | new_group_delay: 0
113 | groupby_simple_monitor: false
114 | renotify_occurrences: 0
115 | renotify_statuses: []
116 | validate: true
117 | no_data_timeframe: 10
118 | threshold_windows:
119 | trigger_window: "last_15m"
120 | recovery_window: "last_15m"
121 | thresholds:
122 | critical: 1
123 | #warning:
124 | #unknown:
125 | #ok:
126 | critical_recovery: 0
127 | #warning_recovery:
128 |
129 | amq-network-out:
130 | name: "(AMQ) Anomaly of a large variance in network-out bytes"
131 | type: metric alert
132 | query: |
133 | avg(last_4h):anomalies(avg:aws.amazonmq.network_out{*} by {broker}, 'agile', 2, direction='both', alert_window='last_15m', interval=60, count_default_zero='true', seasonality='hourly') >= 1
134 | message: |
135 | {{#is_alert}}
136 | ({broker}) - Anomaly of a large variance in network-out bytes
137 | {{/is_alert}}
138 | escalation_message: ""
139 | tags:
140 | ManagedBy: Terraform
141 | priority: 3
142 | notify_no_data: false
143 | notify_audit: true
144 | require_full_window: true
145 | enable_logs_sample: false
146 | force_delete: true
147 | include_tags: true
148 | locked: false
149 | renotify_interval: 60
150 | timeout_h: 0
151 | evaluation_delay: 900
152 | new_host_delay: 300
153 | new_group_delay: 0
154 | groupby_simple_monitor: false
155 | renotify_occurrences: 0
156 | renotify_statuses: []
157 | validate: true
158 | no_data_timeframe: 10
159 | threshold_windows:
160 | trigger_window: "last_15m"
161 | recovery_window: "last_15m"
162 | thresholds:
163 | critical: 1
164 | #warning:
165 | #unknown:
166 | #ok:
167 | critical_recovery: 0
168 | #warning_recovery:
169 |
170 | amq-current-connections-count:
171 | name: "(AMQ) Anomaly of a large variance in broker connections"
172 | type: metric alert
173 | query: |
174 | avg(last_4h):anomalies(avg:aws.amazonmq.current_connections_count{*}.as_count(), 'basic', 2, direction='both', alert_window='last_15m', interval=60, count_default_zero='true') >= 1
175 | message: |
176 | {{#is_alert}}
177 | ({broker}) - Anomaly of a large variance in broker connections
178 | {{/is_alert}}
179 | escalation_message: ""
180 | tags:
181 | ManagedBy: Terraform
182 | priority: 3
183 | notify_no_data: false
184 | notify_audit: true
185 | require_full_window: true
186 | enable_logs_sample: false
187 | force_delete: true
188 | include_tags: true
189 | locked: false
190 | renotify_interval: 60
191 | timeout_h: 0
192 | evaluation_delay: 900
193 | new_host_delay: 300
194 | new_group_delay: 0
195 | groupby_simple_monitor: false
196 | renotify_occurrences: 0
197 | renotify_statuses: []
198 | validate: true
199 | no_data_timeframe: 10
200 | threshold_windows:
201 | trigger_window: "last_15m"
202 | recovery_window: "last_15m"
203 | thresholds:
204 | critical: 1
205 | #warning:
206 | #unknown:
207 | #ok:
208 | critical_recovery: 0
209 | #warning_recovery:
210 |
--------------------------------------------------------------------------------
/catalog/monitors/aurora.yaml:
--------------------------------------------------------------------------------
1 | # The official Datadog API documentation with available query parameters & alert types:
2 | # https://docs.datadoghq.com/api/v1/monitors/#create-a-monitor
3 |
4 | aurora-replica-lag:
5 | name: "(RDS) Aurora Replica Lag Detected"
6 | type: metric alert
7 | query: |
8 | min(last_15m):min:aws.rds.aurora_replica_lag{*} by {dbinstanceidentifier} > 1000
9 | message: |
10 | {{#is_warning}}
11 | ({dbinstanceidentifier}) Replica lag has been greater than half a second for more than 15 minutes
12 | {{/is_warning}}
13 | {{#is_alert}}
14 | ({dbinstanceidentifier}) Replica lag has been greater than 1s for more than 15 minutes
15 | {{/is_alert}}
16 | escalation_message: ""
17 | tags:
18 | ManagedBy: Terraform
19 | priority: 3
20 | notify_no_data: false
21 | notify_audit: true
22 | require_full_window: false
23 | enable_logs_sample: false
24 | force_delete: true
25 | include_tags: true
26 | locked: false
27 | renotify_interval: 60
28 | timeout_h: 0
29 | evaluation_delay: 60
30 | new_host_delay: 300
31 | new_group_delay: 0
32 | groupby_simple_monitor: false
33 | renotify_occurrences: 0
34 | renotify_statuses: []
35 | validate: true
36 | no_data_timeframe: 10
37 | threshold_windows: { }
38 | thresholds:
39 | critical: 1000
40 | warning: 500
41 | #unknown:
42 | #ok:
43 | #critical_recovery:
44 | #warning_recovery:
45 |
--------------------------------------------------------------------------------
/catalog/monitors/ec2.yaml:
--------------------------------------------------------------------------------
1 | # The official Datadog API documentation with available query parameters & alert types:
2 | # https://docs.datadoghq.com/api/v1/monitors/#create-a-monitor
3 |
4 | ec2-failed-status-check:
5 | name: "(EC2) Failed Status Check"
6 | type: metric alert
7 | query: |
8 | avg(last_10m):avg:aws.ec2.status_check_failed{*} by {instance_id} > 0
9 | message: |
10 | ({stage} {region}) {instance_id} failed a status check
11 | escalation_message: ""
12 | tags:
13 | ManagedBy: Terraform
14 | priority: 3
15 | notify_no_data: false
16 | notify_audit: true
17 | require_full_window: true
18 | enable_logs_sample: false
19 | force_delete: true
20 | include_tags: true
21 | locked: false
22 | renotify_interval: 60
23 | timeout_h: 0
24 | evaluation_delay: 60
25 | new_host_delay: 300
26 | new_group_delay: 0
27 | groupby_simple_monitor: false
28 | renotify_occurrences: 0
29 | renotify_statuses: []
30 | validate: true
31 | no_data_timeframe: 10
32 | threshold_windows: { }
33 | thresholds:
34 | critical: 0
35 | #warning:
36 | #unknown:
37 | #ok:
38 | #critical_recovery:
39 | #warning_recovery:
40 |
--------------------------------------------------------------------------------
/catalog/monitors/host.yaml:
--------------------------------------------------------------------------------
1 | # The official Datadog API documentation with available query parameters & alert types:
2 | # https://docs.datadoghq.com/api/v1/monitors/#create-a-monitor
3 |
4 | host-io-wait-times:
5 | name: "(Host) I/O Wait Times"
6 | type: metric alert
7 | query: "avg(last_10m):avg:system.cpu.iowait{*} by {host} > 50"
8 | message: |-
9 | The I/O wait time for ({{host.name}} {{host.ip}}) is very high
10 | escalation_message: ""
11 | tags:
12 | ManagedBy: Terraform
13 | priority: 3
14 | notify_no_data: false
15 | notify_audit: true
16 | require_full_window: true
17 | enable_logs_sample: false
18 | force_delete: true
19 | include_tags: true
20 | locked: false
21 | renotify_interval: 60
22 | timeout_h: 0
23 | evaluation_delay: 60
24 | new_host_delay: 300
25 | new_group_delay: 0
26 | groupby_simple_monitor: false
27 | renotify_occurrences: 0
28 | renotify_statuses: []
29 | validate: true
30 | no_data_timeframe: 10
31 | threshold_windows: { }
32 | thresholds:
33 | critical: 50
34 | warning: 30
35 | #unknown:
36 | #ok:
37 | #critical_recovery:
38 | #warning_recovery:
39 |
40 | host-disk-use:
41 | name: "(Host) Host Disk Usage"
42 | type: metric alert
43 | query: "avg(last_30m):(avg:system.disk.total{*} by {host} - avg:system.disk.free{*} by {host}) / avg:system.disk.total{*} by {host} * 100 > 90"
44 | message: |-
45 | Disk Usage has been above threshold over 30 minutes on ({{host.name}} {{host.ip}})
46 | escalation_message: ""
47 | tags:
48 | ManagedBy: Terraform
49 | priority: 3
50 | notify_no_data: false
51 | notify_audit: true
52 | require_full_window: true
53 | enable_logs_sample: false
54 | force_delete: true
55 | include_tags: true
56 | locked: false
57 | renotify_interval: 60
58 | timeout_h: 0
59 | evaluation_delay: 60
60 | new_host_delay: 300
61 | new_group_delay: 0
62 | groupby_simple_monitor: false
63 | renotify_occurrences: 0
64 | renotify_statuses: []
65 | validate: true
66 | no_data_timeframe: 10
67 | threshold_windows: { }
68 | thresholds:
69 | critical: 90
70 | warning: 80
71 | #unknown:
72 | #ok:
73 | critical_recovery: 85
74 | warning_recovery: 75
75 |
76 | host-high-mem-use:
77 | name: "(Host) Memory Utilization"
78 | type: query alert
79 | query: "avg(last_15m):avg:system.mem.pct_usable{*} by {host} < 0.1"
80 | message: |-
81 | Running out of free memory on ({{host.name}} {{host.ip}})
82 | escalation_message: ""
83 | tags:
84 | ManagedBy: Terraform
85 | priority: 3
86 | notify_no_data: false
87 | notify_audit: true
88 | require_full_window: true
89 | enable_logs_sample: false
90 | force_delete: true
91 | include_tags: true
92 | locked: false
93 | renotify_interval: 60
94 | timeout_h: 0
95 | evaluation_delay: 60
96 | new_host_delay: 300
97 | new_group_delay: 0
98 | groupby_simple_monitor: false
99 | renotify_occurrences: 0
100 | renotify_statuses: []
101 | validate: true
102 | no_data_timeframe: 10
103 | threshold_windows: { }
104 | thresholds:
105 | critical: 0.1
106 | warning: 0.15
107 | #unknown:
108 | #ok:
109 | #critical_recovery:
110 | #warning_recovery:
111 |
112 | host-high-load-avg:
113 | name: "(Host) High System Load Average"
114 | type: metric alert
115 | query: "avg(last_30m):avg:system.load.norm.5{*} by {host} > 2"
116 | message: |-
117 | Load average is high on ({{host.name}} {{host.ip}})
118 | escalation_message: ""
119 | tags:
120 | ManagedBy: Terraform
121 | priority: 3
122 | notify_no_data: false
123 | notify_audit: true
124 | require_full_window: true
125 | enable_logs_sample: false
126 | force_delete: true
127 | include_tags: true
128 | locked: false
129 | renotify_interval: 60
130 | timeout_h: 0
131 | evaluation_delay: 60
132 | new_host_delay: 300
133 | new_group_delay: 0
134 | groupby_simple_monitor: false
135 | renotify_occurrences: 0
136 | renotify_statuses: []
137 | validate: true
138 | no_data_timeframe: 10
139 | threshold_windows: { }
140 | thresholds:
141 | critical: 2
142 | #warning:
143 | #unknown:
144 | #ok:
145 | #critical_recovery:
146 | #warning_recovery:
147 |
--------------------------------------------------------------------------------
/catalog/monitors/rabbitmq.yaml:
--------------------------------------------------------------------------------
1 | rabbitmq-messages-unacknowledged-rate-too-high:
2 | name: "[RabbitMQ] - Messages unacknowledged rate is higher than usual on: {{host.name}}"
3 | type: "query alert"
4 | query: |
5 | avg(last_4h):anomalies(avg:rabbitmq.queue.messages_unacknowledged.rate{*} by {rabbitmq_queue,host}, 'agile', 2, direction='above', alert_window='last_15m', interval=60, count_default_zero='true', seasonality='hourly') >= 1
6 | message: |
7 | The rate at which messages are being delivered without receiving acknowledgement is higher than usual.
8 | There may be errors or performance issues downstream.\n
9 | Host: {{host.name}}\n
10 | RabbitMQ Queue: {{rabbitmq_queue.name}}
11 | escalation_message: ""
12 | tags:
13 | ManagedBy: Terraform
14 | Integration: RabbitMQ
15 | priority: 3
16 | notify_no_data: false
17 | notify_audit: true
18 | require_full_window: true
19 | enable_logs_sample: false
20 | force_delete: true
21 | include_tags: true
22 | locked: false
23 | renotify_interval: 0
24 | timeout_h: 0
25 | evaluation_delay: 60
26 | new_host_delay: 300
27 | new_group_delay: 0
28 | groupby_simple_monitor: false
29 | renotify_occurrences: 0
30 | renotify_statuses: []
31 | validate: true
32 | no_data_timeframe: null
33 | threshold_windows: { }
34 | thresholds:
35 | critical: 1
36 | critical_recovery: 0
37 | #warning:
38 | #unknown:
39 | #ok:
40 | #warning_recovery:
41 |
42 | rabbitmq-disk-usage-too-high:
43 | name: "[RabbitMQ] Level of disk usage is too high for host: {{host.name}}"
44 | type: "query alert"
45 | query: |
46 | avg(last_5m):avg:rabbitmq.node.mem_used{*} by {host} / avg:system.mem.total{*} by {host} * 100 > 35
47 | message: |
48 | RabbitMQ is using too many resources on host: {{host.name}}.
49 | It may block connections and won't be able to perform many internal operations.
50 | escalation_message: ""
51 | tags:
52 | ManagedBy: Terraform
53 | Integration: RabbitMQ
54 | priority: 3
55 | notify_no_data: false
56 | notify_audit: true
57 | require_full_window: true
58 | enable_logs_sample: false
59 | force_delete: true
60 | include_tags: true
61 | locked: false
62 | renotify_interval: 0
63 | timeout_h: 0
64 | evaluation_delay: 60
65 | new_host_delay: 300
66 | new_group_delay: 0
67 | groupby_simple_monitor: false
68 | renotify_occurrences: 0
69 | renotify_statuses: []
70 | validate: true
71 | no_data_timeframe: null
72 | threshold_windows: { }
73 | thresholds:
74 | critical: 35
75 | warning: 30
76 | #unknown:
77 | #ok:
78 | #critical_recovery:
79 | #warning_recovery:
80 |
--------------------------------------------------------------------------------
/catalog/monitors/rds.yaml:
--------------------------------------------------------------------------------
1 | # The official Datadog API documentation with available query parameters & alert types:
2 | # https://docs.datadoghq.com/api/v1/monitors/#create-a-monitor
3 |
4 | rds-cpuutilization:
5 | name: "(RDS) CPU Utilization above 90%"
6 | type: metric alert
7 | query: |
8 | avg(last_15m):avg:aws.rds.cpuutilization{*} by {dbinstanceidentifier} > 90
9 | message: |
10 | {{#is_warning}}
11 | ({dbinstanceidentifier}) CPU Utilization above 85%
12 | {{/is_warning}}
13 | {{#is_alert}}
14 | ({dbinstanceidentifier}) CPU Utilization above 90%
15 | {{/is_alert}}
16 | escalation_message: ""
17 | tags:
18 | ManagedBy: Terraform
19 | priority: 3
20 | notify_no_data: false
21 | notify_audit: true
22 | require_full_window: true
23 | enable_logs_sample: false
24 | force_delete: true
25 | include_tags: true
26 | locked: false
27 | renotify_interval: 60
28 | timeout_h: 0
29 | evaluation_delay: 60
30 | new_host_delay: 300
31 | new_group_delay: 0
32 | groupby_simple_monitor: false
33 | renotify_occurrences: 0
34 | renotify_statuses: []
35 | validate: true
36 | no_data_timeframe: 10
37 | threshold_windows: { }
38 | thresholds:
39 | critical: 90
40 | warning: 85
41 | #unknown:
42 | #ok:
43 | #critical_recovery:
44 | #warning_recovery:
45 |
46 | rds-disk-queue-depth:
47 | name: "(RDS) Disk queue depth above 64"
48 | type: metric alert
49 | query: |
50 | avg(last_15m):avg:aws.rds.disk_queue_depth{*} by {dbinstanceidentifier} > 64
51 | message: |
52 | {{#is_warning}}
53 | ({dbinstanceidentifier}) Disk queue depth above 48
54 | {{/is_warning}}
55 | {{#is_alert}}
56 | ({dbinstanceidentifier}) Disk queue depth above 64
57 | {{/is_alert}}
58 | escalation_message: ""
59 | tags:
60 | ManagedBy: Terraform
61 | priority: 3
62 | notify_no_data: false
63 | notify_audit: true
64 | require_full_window: true
65 | enable_logs_sample: false
66 | force_delete: true
67 | include_tags: true
68 | locked: false
69 | renotify_interval: 60
70 | timeout_h: 0
71 | evaluation_delay: 60
72 | new_host_delay: 300
73 | new_group_delay: 0
74 | groupby_simple_monitor: false
75 | renotify_occurrences: 0
76 | renotify_statuses: []
77 | validate: true
78 | no_data_timeframe: 10
79 | threshold_windows: { }
80 | thresholds:
81 | critical: 64
82 | warning: 48
83 | #unknown:
84 | #ok:
85 | #critical_recovery:
86 | #warning_recovery:
87 |
88 | rds-freeable-memory:
89 | name: "(RDS) Freeable memory below 256 MB"
90 | type: metric alert
91 | query: |
92 | avg(last_5m):avg:aws.rds.freeable_memory{*} < 256000000
93 | message: |
94 | {{#is_warning}}
95 | ({dbinstanceidentifier}) Freeable memory below 512 MB
96 | {{/is_warning}}
97 | {{#is_alert}}
98 | ({dbinstanceidentifier}) Freeable memory below 256 MB
99 | {{/is_alert}}
100 | escalation_message: ""
101 | tags:
102 | ManagedBy: Terraform
103 | priority: 3
104 | notify_no_data: false
105 | notify_audit: true
106 | require_full_window: true
107 | enable_logs_sample: false
108 | force_delete: true
109 | include_tags: true
110 | locked: false
111 | renotify_interval: 60
112 | timeout_h: 0
113 | evaluation_delay: 60
114 | new_host_delay: 300
115 | new_group_delay: 0
116 | groupby_simple_monitor: false
117 | renotify_occurrences: 0
118 | renotify_statuses: []
119 | validate: true
120 | no_data_timeframe: 10
121 | threshold_windows: { }
122 | thresholds:
123 | critical: 256000000
124 | warning: 512000000
125 | #unknown:
126 | #ok:
127 | #critical_recovery:
128 | #warning_recovery:
129 |
130 | rds-swap-usage:
131 | name: "(RDS) Swap usage above 256 MB"
132 | type: metric alert
133 | query: |
134 | avg(last_15m):avg:aws.rds.swap_usage{*} by {dbinstanceidentifier} > 256000000
135 | message: |
136 | {{#is_warning}}
137 | ({dbinstanceidentifier}) Swap usage above 128 MB
138 | {{/is_warning}}
139 | {{#is_alert}}
140 | ({dbinstanceidentifier}) Swap usage above 256 MB
141 | {{/is_alert}}
142 | escalation_message: ""
143 | tags:
144 | ManagedBy: Terraform
145 | priority: 3
146 | notify_no_data: false
147 | notify_audit: true
148 | require_full_window: true
149 | enable_logs_sample: false
150 | force_delete: true
151 | include_tags: true
152 | locked: false
153 | renotify_interval: 60
154 | timeout_h: 0
155 | evaluation_delay: 60
156 | new_host_delay: 300
157 | new_group_delay: 0
158 | groupby_simple_monitor: false
159 | renotify_occurrences: 0
160 | renotify_statuses: []
161 | validate: true
162 | no_data_timeframe: 10
163 | threshold_windows: { }
164 | thresholds:
165 | critical: 256000000
166 | warning: 128000000
167 | #unknown:
168 | #ok:
169 | #critical_recovery:
170 | #warning_recovery:
171 |
172 | rds-database-connections:
173 | name: "(RDS) Anomaly of a large variance in RDS connection count"
174 | type: metric alert
175 | query: |
176 | avg(last_4h):anomalies(avg:aws.rds.database_connections{*}, 'basic', 2, direction='both', alert_window='last_15m', interval=60, count_default_zero='true') >= 1
177 | message: |
178 | {{#is_warning}}
179 | ({dbinstanceidentifier}) Anomaly of a large variance in RDS connection count
180 | {{/is_warning}}
181 | {{#is_alert}}
182 | ({dbinstanceidentifier}) Anomaly of a large variance in RDS connection count
183 | {{/is_alert}}
184 | escalation_message: ""
185 | tags:
186 | ManagedBy: Terraform
187 | priority: 3
188 | notify_no_data: false
189 | notify_audit: true
190 | require_full_window: true
191 | enable_logs_sample: false
192 | force_delete: true
193 | include_tags: true
194 | locked: false
195 | renotify_interval: 60
196 | timeout_h: 0
197 | evaluation_delay: 60
198 | new_host_delay: 300
199 | new_group_delay: 0
200 | groupby_simple_monitor: false
201 | renotify_occurrences: 0
202 | renotify_statuses: []
203 | validate: true
204 | no_data_timeframe: 10
205 | threshold_windows:
206 | trigger_window: "last_15m"
207 | recovery_window: "last_15m"
208 | thresholds:
209 | critical: 1
210 | #warning:
211 | #unknown:
212 | #ok:
213 | critical_recovery: 0
214 | #warning_recovery:
215 |
--------------------------------------------------------------------------------
/catalog/roles/admin.yaml:
--------------------------------------------------------------------------------
1 | admin:
2 | name: "Admin"
3 | permissions:
4 | - "admin"
5 |
--------------------------------------------------------------------------------
/catalog/roles/api.yaml:
--------------------------------------------------------------------------------
1 | api-keys-read:
2 | name: "API keys read"
3 | permissions:
4 | - "api_keys_read"
5 |
6 | api-keys-write:
7 | name: "API keys write"
8 | permissions:
9 | - "api_keys_write"
10 |
--------------------------------------------------------------------------------
/catalog/roles/apm.yaml:
--------------------------------------------------------------------------------
1 | apm-apdex-manage-write:
2 | name: "APM apdex manage write"
3 | permissions:
4 | - "apm_apdex_manage_write"
5 |
6 | apm-primary-operation-write:
7 | name: "APM primary operation write"
8 | permissions:
9 | - "apm_primary_operation_write"
10 |
11 | apm-retention-filter-read:
12 | name: "APM retention filter read"
13 | permissions:
14 | - "apm_retention_filter_read"
15 |
16 | apm-retention-filter-write:
17 | name: "APM retention filter write"
18 | permissions:
19 | - "apm_retention_filter_write"
20 |
21 | apm-service-ingest-read:
22 | name: "APM service ingest read"
23 | permissions:
24 | - "apm_service_ingest_read"
25 |
26 | apm-service-ingest-write:
27 | name: "APM service ingest write"
28 | permissions:
29 | - "apm_service_ingest_write"
30 |
31 | apm-tag-management-write:
32 | name: "APM tag management write"
33 | permissions:
34 | - "apm_tag_management_write"
35 |
--------------------------------------------------------------------------------
/catalog/roles/billing.yaml:
--------------------------------------------------------------------------------
1 | billing-edit:
2 | name: "Billing edit"
3 | permissions:
4 | - "billing_edit"
5 |
6 | billing-read:
7 | name: "Billing read"
8 | permissions:
9 | - "billing_read"
10 |
--------------------------------------------------------------------------------
/catalog/roles/dashboards.yaml:
--------------------------------------------------------------------------------
1 | dashboards-public-share:
2 | name: "Dashboards public share"
3 | permissions:
4 | - "dashboards_public_share"
5 |
6 | dashboards-write:
7 | name: "Dashboards write"
8 | permissions:
9 | - "dashboards_write"
10 |
--------------------------------------------------------------------------------
/catalog/roles/data.yaml:
--------------------------------------------------------------------------------
1 | data-scanner-read:
2 | name: "Data scanner read"
3 | permissions:
4 | - "data_scanner_read"
5 |
6 | data-scanner-write:
7 | name: "Data scanner write"
8 | permissions:
9 | - "data_scanner_write"
10 |
--------------------------------------------------------------------------------
/catalog/roles/incident.yaml:
--------------------------------------------------------------------------------
1 | incident-settings-read:
2 | name: "Incident settings read"
3 | permissions:
4 | - "incident_settings_read"
5 |
6 | incident-settings-write:
7 | name: "Incident settings write"
8 | permissions:
9 | - "incident_settings_write"
10 |
11 | incident-write:
12 | name: "Incident write"
13 | permissions:
14 | - "incident_write"
15 |
--------------------------------------------------------------------------------
/catalog/roles/integrations.yaml:
--------------------------------------------------------------------------------
1 | integrations-api:
2 | name: "Integrations API"
3 | permissions:
4 | - "integrations_api"
5 |
--------------------------------------------------------------------------------
/catalog/roles/logs.yaml:
--------------------------------------------------------------------------------
1 | logs-generate-metrics:
2 | name: "Logs generate metrics"
3 | permissions:
4 | - "logs_generate_metrics"
5 |
6 | logs-live-tail:
7 | name: "Logs live tail"
8 | permissions:
9 | - "logs_live_tail"
10 |
11 | logs-modify-indexes:
12 | name: "Logs modify indexes"
13 | permissions:
14 | - "logs_modify_indexes"
15 |
16 | logs-public-config-api:
17 | name: "Logs public config api"
18 | permissions:
19 | - "logs_public_config_api"
20 |
21 | logs-read-archives:
22 | name: "Logs read archives"
23 | permissions:
24 | - "logs_read_archives"
25 |
26 | logs-read-data:
27 | name: "Logs read data"
28 | permissions:
29 | - "logs_read_data"
30 |
31 | logs-read-index-data:
32 | name: "Logs read index data"
33 | permissions:
34 | - "logs_read_index_data"
35 |
36 | logs-write-archives:
37 | name: "Logs write archives"
38 | permissions:
39 | - "logs_write_archives"
40 |
41 | logs-write-exclusion-filters:
42 | name: "Logs write exclusion filters"
43 | permissions:
44 | - "logs_write_exclusion_filters"
45 |
46 | logs-write-facets:
47 | name: "Logs write facets"
48 | permissions:
49 | - "logs_write_facets"
50 |
51 | logs-write-historical-view:
52 | name: "Logs write historical view"
53 | permissions:
54 | - "logs_write_historical_view"
55 |
56 | logs-write-pipelines:
57 | name: "Logs write pipelines"
58 | permissions:
59 | - "logs_write_pipelines"
60 |
61 | logs-write-processors:
62 | name: "Logs write processors"
63 | permissions:
64 | - "logs_write_processors"
65 |
--------------------------------------------------------------------------------
/catalog/roles/metric.yaml:
--------------------------------------------------------------------------------
1 | metric-tags-write:
2 | name: "Metric tags write"
3 | permissions:
4 | - "metric_tags_write"
5 |
--------------------------------------------------------------------------------
/catalog/roles/monitors.yaml:
--------------------------------------------------------------------------------
1 | monitors-write:
2 | name: "Monitors write"
3 | permissions:
4 | - "monitors_write"
5 |
6 | monitors-downtime:
7 | name: "Monitors downtime"
8 | permissions:
9 | - "monitors_downtime"
10 |
--------------------------------------------------------------------------------
/catalog/roles/org.yaml:
--------------------------------------------------------------------------------
1 | org-app-keys-read:
2 | name: "Org app keys read"
3 | permissions:
4 | - "org_app_keys_read"
5 |
6 | org-app-keys-write:
7 | name: "Org app keys write"
8 | permissions:
9 | - "org_app_keys_write"
10 |
--------------------------------------------------------------------------------
/catalog/roles/rum.yaml:
--------------------------------------------------------------------------------
1 | rum-apps-write:
2 | name: "Rum apps write"
3 | permissions:
4 | - "rum_apps_write"
5 |
--------------------------------------------------------------------------------
/catalog/roles/security.yaml:
--------------------------------------------------------------------------------
1 | security-monitoring-filters-read:
2 | name: "Security monitoring filters read"
3 | permissions:
4 | - "security_monitoring_filters_read"
5 |
6 | security-monitoring-filters-write:
7 | name: "Security monitoring filters write"
8 | permissions:
9 | - "security_monitoring_filters_write"
10 |
11 | security-monitoring-rules-read:
12 | name: "Security monitoring rules read"
13 | permissions:
14 | - "security_monitoring_rules_read"
15 |
16 | security-monitoring-rules-write:
17 | name: "Security monitoring rules write"
18 | permissions:
19 | - "security_monitoring_rules_write"
20 |
21 | security-monitoring-signals-read:
22 | name: "Security monitoring signals read"
23 | permissions:
24 | - "security_monitoring_signals_read"
25 |
--------------------------------------------------------------------------------
/catalog/roles/standard.yaml:
--------------------------------------------------------------------------------
1 | standard:
2 | name: "Standard"
3 | permissions:
4 | - "standard"
5 |
--------------------------------------------------------------------------------
/catalog/roles/synthetics.yaml:
--------------------------------------------------------------------------------
1 | synthetics-default-settings-read:
2 | name: "Synthetics default settings read"
3 | permissions:
4 | - "synthetics_default_settings_read"
5 |
6 | synthetics-default-settings-write:
7 | name: "Synthetics default settings write"
8 | permissions:
9 | - "synthetics_default_settings_write"
10 |
11 | synthetics-global-variable-read:
12 | name: "Synthetics global variable read"
13 | permissions:
14 | - "synthetics_global_variable_read"
15 |
16 | synthetics-global-variable-write:
17 | name: "Synthetics global variable write"
18 | permissions:
19 | - "synthetics_global_variable_write"
20 |
21 | synthetics-private-location-read:
22 | name: "Synthetics private location read"
23 | permissions:
24 | - "synthetics_private_location_read"
25 |
26 | synthetics-private-location-write:
27 | name: "Synthetics private location write"
28 | permissions:
29 | - "synthetics_private_location_write"
30 |
31 | synthetics-read:
32 | name: "Synthetics read"
33 | permissions:
34 | - "synthetics_read"
35 |
36 | synthetics-write:
37 | name: "Synthetics write"
38 | permissions:
39 | - "synthetics_write"
40 |
--------------------------------------------------------------------------------
/catalog/roles/usage.yaml:
--------------------------------------------------------------------------------
1 | usage-edit:
2 | name: "Usage edit"
3 | permissions:
4 | - "usage_edit"
5 |
6 | usage-read:
7 | name: "Usage read"
8 | permissions:
9 | - "usage_read"
10 |
--------------------------------------------------------------------------------
/catalog/roles/user.yaml:
--------------------------------------------------------------------------------
1 | user-access-invite:
2 | name: "User access invite"
3 | permissions:
4 | - "user_access_invite"
5 |
6 | user-access-manage:
7 | name: "User access manage"
8 | permissions:
9 | - "user_access_manage"
10 |
11 | user-app-keys:
12 | name: "User app keys"
13 | permissions:
14 | - "user_app_keys"
15 |
--------------------------------------------------------------------------------
/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/child_organization/fixtures.us-east-2.tfvars:
--------------------------------------------------------------------------------
1 | namespace = "eg"
2 |
3 | stage = "test"
4 |
5 | name = "datadog-child-org"
6 |
7 | organization_name = "test"
8 |
--------------------------------------------------------------------------------
/examples/child_organization/main.tf:
--------------------------------------------------------------------------------
1 | module "datadog_child_organization" {
2 | source = "../../modules/child_organization"
3 |
4 | organization_name = var.organization_name
5 |
6 | context = module.this.context
7 | }
8 |
--------------------------------------------------------------------------------
/examples/child_organization/outputs.tf:
--------------------------------------------------------------------------------
1 | output "id" {
2 | value = module.datadog_child_organization.id
3 | description = "Organization ID"
4 | }
5 |
6 | output "description" {
7 | value = module.datadog_child_organization.description
8 | description = "Description of the organization"
9 | }
10 |
11 | output "public_id" {
12 | value = module.datadog_child_organization.public_id
13 | description = "Public ID of the organization"
14 | }
15 |
16 | output "user" {
17 | value = module.datadog_child_organization.user
18 | description = "Information about organization users"
19 | }
20 |
21 | output "settings" {
22 | value = module.datadog_child_organization.settings
23 | description = "Organization settings"
24 | }
25 |
--------------------------------------------------------------------------------
/examples/child_organization/providers.tf:
--------------------------------------------------------------------------------
1 | # For the example, we use ENV variables `DD_API_KEY` and `DD_APP_KEY` in place of the `api_key` and `app_key` parameters to the provider
2 | # https://registry.terraform.io/providers/DataDog/datadog/latest/docs#argument-reference
3 | provider "datadog" {
4 | validate = false
5 | }
6 |
--------------------------------------------------------------------------------
/examples/child_organization/variables.tf:
--------------------------------------------------------------------------------
1 | # https://docs.datadoghq.com/account_management/org_settings/#overview
2 |
3 | variable "organization_name" {
4 | type = string
5 | description = "Datadog organization name"
6 | }
7 |
--------------------------------------------------------------------------------
/examples/child_organization/versions.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_version = ">= 1.0.0"
3 |
4 | required_providers {
5 | datadog = {
6 | source = "datadog/datadog"
7 | version = ">= 3.0.0"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/examples/complete/fixtures.us-east-2.tfvars:
--------------------------------------------------------------------------------
1 | namespace = "eg"
2 |
3 | stage = "test"
4 |
5 | name = "datadog-monitor"
6 |
7 | alert_tags = ["@opsgenie"]
8 |
9 | alert_tags_separator = "\n"
10 |
11 | legacy_monitor_paths = ["./monitors-test/*.yaml"]
12 |
13 | json_monitor_paths = ["./monitors-test/*.json"]
14 |
--------------------------------------------------------------------------------
/examples/complete/main.tf:
--------------------------------------------------------------------------------
1 | locals {
2 | # Note that we do not follow the usual pattern of using the `attributes` in the resource ID.
3 | # This is because we do not have automatic cleanup of the monitors, and we want to avoid
4 | # leaving orphaned monitors around. This way, tests will fail if they find an orphaned
5 | # monitor already exists, and we will know to clean it up manually.
6 | legacy_monitor_files = flatten([for p in var.legacy_monitor_paths : fileset(path.module, p)])
7 | legacy_monitor_list = [for f in local.legacy_monitor_files : yamldecode(file(f))]
8 | legacy_monitor_map = merge(local.legacy_monitor_list...)
9 |
10 | json_monitor_files = flatten([for p in var.json_monitor_paths : fileset(path.module, p)])
11 | json_monitor_list = [for f in local.json_monitor_files : jsondecode(file(f))]
12 | json_monitor_map = { for v in local.json_monitor_list : v.name => v }
13 |
14 | monitor_map = merge(local.legacy_monitor_map, local.json_monitor_map)
15 | }
16 |
17 | module "datadog_monitors" {
18 | source = "../../modules/monitors"
19 |
20 | datadog_monitors = local.monitor_map
21 | alert_tags = var.alert_tags
22 | alert_tags_separator = var.alert_tags_separator
23 |
24 | context = module.this.context
25 | }
26 |
--------------------------------------------------------------------------------
/examples/complete/monitors-test/anomaly-recovery-legacy-test.yaml:
--------------------------------------------------------------------------------
1 | anomaly-recovery-legacy-test:
2 | name: anomaly recovery legacy test
3 | type: query alert
4 | query: avg(last_1d):anomalies(avg:system.load.1{*}, 'agile', 2, direction='both', interval=300, alert_window='last_37m', count_default_zero='true', seasonality='weekly') >= 1
5 | message: recovery window test
6 | tags:
7 | ManagedBy: Terraform
8 | Terratest:
9 | thresholds:
10 | critical: 1
11 | critical_recovery: 0
12 | warning: 0.8
13 | notify_audit: false
14 | require_full_window: false
15 | notify_no_data: false
16 | renotify_interval: 0
17 | threshold_windows:
18 | trigger_window: last_37m
19 | recovery_window: last_1h
20 | include_tags: false
21 | timeout_h: 1
22 | evaluation_delay: 88
23 | new_host_delay: 300
24 | priority: 5
25 | restricted_roles: null
26 |
--------------------------------------------------------------------------------
/examples/complete/monitors-test/anomaly-recovery-test.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "anomaly-recovery-test",
3 | "type": "query alert",
4 | "query": "avg(last_1d):anomalies(avg:system.load.1{*}, 'agile', 2, direction='both', interval=300, alert_window='last_37m', count_default_zero='true', seasonality='weekly') >= 1",
5 | "message": "recovery window test",
6 | "tags": [],
7 | "options": {
8 | "thresholds": {
9 | "critical": 1,
10 | "critical_recovery": 0,
11 | "warning": 0.8
12 | },
13 | "notify_audit": false,
14 | "require_full_window": false,
15 | "notify_no_data": false,
16 | "renotify_interval": 0,
17 | "threshold_windows": {
18 | "trigger_window": "last_37m",
19 | "recovery_window": "last_1h"
20 | },
21 | "include_tags": false,
22 | "timeout_h": 1,
23 | "evaluation_delay": 88,
24 | "new_host_delay": 300,
25 | "silenced": {}
26 | },
27 | "priority": 5,
28 | "restricted_roles": null
29 | }
30 |
--------------------------------------------------------------------------------
/examples/complete/monitors-test/monitor-variables-test.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "monitor-variables-test",
3 | "type": "event-v2 alert",
4 | "query": "formula(\"query2 / query1 * 100\").last(\"15m\") > 0.8",
5 | "message": "Test of monitors with variables",
6 | "tags": [
7 | "test:examplemonitor",
8 | "env:ci"
9 | ],
10 | "options": {
11 | "thresholds": {
12 | "critical": 0.8
13 | },
14 | "enable_logs_sample": false,
15 | "notify_audit": false,
16 | "on_missing_data": "default",
17 | "include_tags": false,
18 | "variables": [
19 | {
20 | "data_source": "events",
21 | "name": "query2",
22 | "indexes": [
23 | "*"
24 | ],
25 | "compute": {
26 | "aggregation": "count"
27 | },
28 | "group_by": [],
29 | "search": {
30 | "query": "status:error"
31 | },
32 | "storage": "hot"
33 | },
34 | {
35 | "data_source": "events",
36 | "name": "query1",
37 | "indexes": [
38 | "*"
39 | ],
40 | "compute": {
41 | "aggregation": "count"
42 | },
43 | "group_by": [],
44 | "search": {
45 | "query": ""
46 | },
47 | "storage": "hot"
48 | }
49 | ],
50 | "new_host_delay": 300,
51 | "groupby_simple_monitor": false,
52 | "silenced": {}
53 | },
54 | "priority": 5,
55 | "restricted_roles": null
56 | }
57 |
--------------------------------------------------------------------------------
/examples/complete/monitors-test/schedule-legacy-test.yaml:
--------------------------------------------------------------------------------
1 | schedule-legacy-test:
2 | name: schedule-legacy-test
3 | type: event-v2 alert
4 | query: events("service:datadog-agent").rollup("cardinality", "@evt.id").current("1h") > 2345
5 | message: No message
6 | threshold_windows: {}
7 | thresholds:
8 | critical: 2345
9 | warning: 987
10 | enable_logs_sample: false
11 | notify_audit: false
12 | on_missing_data: default
13 | include_tags: false
14 | scheduling_options:
15 | - evaluation_window:
16 | - hour_starts: 7
17 | priority: 5
18 |
--------------------------------------------------------------------------------
/examples/complete/monitors-test/schedule-test.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "schedule-test",
3 | "type": "event-v2 alert",
4 | "query": "events(\"service:datadog-agent\").rollup(\"cardinality\", \"@evt.id\").current(\"1h\") > 2345",
5 | "message": "No message",
6 | "tags": [
7 | "test:examplemonitor",
8 | "Terratest"
9 | ],
10 | "options": {
11 | "thresholds": {
12 | "critical": 2345,
13 | "warning": 987
14 | },
15 | "enable_logs_sample": false,
16 | "notify_audit": false,
17 | "on_missing_data": "default",
18 | "include_tags": false,
19 | "scheduling_options": {
20 | "custom_schedule": {
21 | "recurrences": [
22 | {
23 | "rrule": "FREQ=DAILY;INTERVAL=1;BYHOUR=17;BYMINUTE=54",
24 | "timezone": "America/Los_Angeles"
25 | }
26 | ]
27 | },
28 | "evaluation_window": {
29 | "hour_starts": 7
30 | }
31 | }
32 | },
33 | "priority": 5
34 | }
35 |
--------------------------------------------------------------------------------
/examples/complete/outputs.tf:
--------------------------------------------------------------------------------
1 | output "datadog_monitor_names" {
2 | value = module.datadog_monitors.datadog_monitor_names
3 | description = "Names of the created Datadog monitors"
4 | }
5 |
6 | output "datadog_monitors" {
7 | value = module.datadog_monitors.datadog_monitors
8 | description = "Datadog monitor outputs"
9 | }
10 |
--------------------------------------------------------------------------------
/examples/complete/providers.tf:
--------------------------------------------------------------------------------
1 | # For the example, we use ENV variables `DD_API_KEY` and `DD_APP_KEY` in place of the `api_key` and `app_key` parameters to the provider
2 | # https://registry.terraform.io/providers/DataDog/datadog/latest/docs#argument-reference
3 | provider "datadog" {
4 | }
5 |
--------------------------------------------------------------------------------
/examples/complete/variables.tf:
--------------------------------------------------------------------------------
1 | variable "alert_tags" {
2 | type = list(string)
3 | description = "List of alert tags to add to all alert messages, e.g. `[\"@opsgenie\"]` or `[\"@devops\", \"@opsgenie\"]`"
4 | }
5 |
6 | variable "alert_tags_separator" {
7 | type = string
8 | description = "Separator for the alert tags. All strings from the `alert_tags` variable will be joined into one string using the separator and then added to the alert message"
9 | }
10 |
11 | variable "legacy_monitor_paths" {
12 | type = list(string)
13 | description = "List of paths to legacy Datadog monitor configurations"
14 | }
15 |
16 | variable "json_monitor_paths" {
17 | type = list(string)
18 | description = "List of paths to JSON Datadog monitor configurations"
19 | }
20 |
--------------------------------------------------------------------------------
/examples/complete/versions.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_version = ">= 1.0.0"
3 |
4 | required_providers {
5 | datadog = {
6 | source = "datadog/datadog"
7 | version = ">= 3.0.0"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/examples/organization_settings/fixtures.us-east-2.tfvars:
--------------------------------------------------------------------------------
1 | namespace = "eg"
2 |
3 | stage = "test"
4 |
5 | name = "datadog-org-settings"
6 |
7 | organization_name = "test"
8 |
9 | # Free and Trial organizations cannot enable SAML
10 | saml_enabled = false
11 |
12 | saml_autocreate_users_domains = []
13 |
14 | saml_autocreate_users_enabled = false
15 |
16 | saml_idp_initiated_login_enabled = false
17 |
18 | saml_strict_mode_enabled = false
19 |
20 | private_widget_share = false
21 |
22 | saml_autocreate_access_role = "ro"
23 |
--------------------------------------------------------------------------------
/examples/organization_settings/main.tf:
--------------------------------------------------------------------------------
1 | module "datadog_organization_settings" {
2 | source = "../../modules/organization_settings"
3 |
4 | organization_name = var.organization_name
5 | saml_enabled = var.saml_enabled
6 | saml_autocreate_users_domains = var.saml_autocreate_users_domains
7 | saml_autocreate_users_enabled = var.saml_autocreate_users_enabled
8 | saml_idp_initiated_login_enabled = var.saml_idp_initiated_login_enabled
9 | saml_strict_mode_enabled = var.saml_strict_mode_enabled
10 | private_widget_share = var.private_widget_share
11 | saml_autocreate_access_role = var.saml_autocreate_access_role
12 |
13 | context = module.this.context
14 | }
15 |
--------------------------------------------------------------------------------
/examples/organization_settings/outputs.tf:
--------------------------------------------------------------------------------
1 | output "id" {
2 | value = module.datadog_organization_settings.id
3 | description = "Organization ID"
4 | }
5 |
6 | output "description" {
7 | value = module.datadog_organization_settings.description
8 | description = "Description of the organization"
9 | }
10 |
11 | output "public_id" {
12 | value = module.datadog_organization_settings.public_id
13 | description = "Public ID of the organization"
14 | }
15 |
16 | output "settings" {
17 | value = module.datadog_organization_settings.settings
18 | description = "Organization settings"
19 | }
20 |
--------------------------------------------------------------------------------
/examples/organization_settings/providers.tf:
--------------------------------------------------------------------------------
1 | # For the example, we use ENV variables `DD_API_KEY` and `DD_APP_KEY` in place of the `api_key` and `app_key` parameters to the provider
2 | # https://registry.terraform.io/providers/DataDog/datadog/latest/docs#argument-reference
3 | provider "datadog" {
4 | validate = false
5 | }
6 |
--------------------------------------------------------------------------------
/examples/organization_settings/variables.tf:
--------------------------------------------------------------------------------
1 | # https://docs.datadoghq.com/account_management/org_settings/#overview
2 |
3 | variable "organization_name" {
4 | type = string
5 | description = "Datadog organization name"
6 | }
7 |
8 | variable "saml_enabled" {
9 | type = bool
10 | default = true
11 | description = "Whether or not SAML is enabled for the child organization. Note that Free and Trial organizations cannot enable SAML"
12 | }
13 |
14 | variable "saml_autocreate_users_domains" {
15 | type = list(string)
16 | default = []
17 | description = "List of domains where the SAML automated user creation is enabled"
18 | }
19 |
20 | variable "saml_autocreate_users_enabled" {
21 | type = bool
22 | default = false
23 | description = "Whether or not the automated user creation based on SAML domain is enabled"
24 | }
25 |
26 | variable "saml_idp_initiated_login_enabled" {
27 | type = bool
28 | default = true
29 | description = "Whether or not IdP initiated login is enabled for the Datadog organization"
30 | }
31 |
32 | variable "saml_strict_mode_enabled" {
33 | type = bool
34 | default = false
35 | description = "Whether or not the SAML strict mode is enabled. If true, all users must log in with SAML"
36 | }
37 |
38 | variable "private_widget_share" {
39 | type = bool
40 | default = false
41 | description = "Whether or not the organization users can share widgets outside of Datadog"
42 | }
43 |
44 | variable "saml_autocreate_access_role" {
45 | type = string
46 | default = "ro"
47 | description = "The access role of an autocreated user. Options are `st` (standard user), `adm` (admin user), or `ro` (read-only user). Allowed enum values: `st`, `adm` , `ro`, `ERROR`"
48 | }
49 |
--------------------------------------------------------------------------------
/examples/organization_settings/versions.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_version = ">= 1.0.0"
3 |
4 | required_providers {
5 | datadog = {
6 | source = "datadog/datadog"
7 | version = ">= 3.0.0"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/examples/rbac/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/rbac/fixtures.us-east-2.tfvars:
--------------------------------------------------------------------------------
1 | namespace = "eg"
2 |
3 | stage = "test"
4 |
5 | name = "datadog-monitor"
6 |
7 | alert_tags = ["@opsgenie"]
8 |
9 | alert_tags_separator = "\n"
10 |
11 | monitor_paths = ["../../catalog/monitors/*.yaml"]
12 |
13 | role_paths = ["../../catalog/roles/monitors.yaml"]
14 |
--------------------------------------------------------------------------------
/examples/rbac/main.tf:
--------------------------------------------------------------------------------
1 | module "monitor_configs" {
2 | source = "cloudposse/config/yaml"
3 | version = "1.0.2"
4 |
5 | map_config_local_base_path = path.module
6 | map_config_paths = var.monitor_paths
7 |
8 | context = module.this.context
9 | }
10 |
11 | module "role_configs" {
12 | source = "cloudposse/config/yaml"
13 | version = "1.0.2"
14 |
15 | map_config_local_base_path = path.module
16 | map_config_paths = var.role_paths
17 |
18 | context = module.this.context
19 | }
20 |
21 | locals {
22 | # Example of assigning restricted roles with permissions to monitors.
23 | # See `catalog/monitors` for the available monitors.
24 | # See `catalog/roles` for the available roles.
25 | # Only these roles will have access to the monitors.
26 | # The Datadog users that are associated with the roles will have the corresponding monitor permissions
27 |
28 | monitors_write_role_name = module.datadog_roles.datadog_roles["monitors-write"].name
29 | monitors_downtime_role_name = module.datadog_roles.datadog_roles["monitors-downtime"].name
30 |
31 | monitors_roles_map = {
32 | aurora-replica-lag = [local.monitors_write_role_name, local.monitors_downtime_role_name]
33 | ec2-failed-status-check = [local.monitors_write_role_name, local.monitors_downtime_role_name]
34 | redshift-health-status = [local.monitors_downtime_role_name]
35 | k8s-deployment-replica-pod-down = [local.monitors_write_role_name]
36 | }
37 | }
38 |
39 | module "datadog_roles" {
40 | source = "../../modules/roles"
41 |
42 | datadog_roles = module.role_configs.map_configs
43 |
44 | context = module.this.context
45 | }
46 |
47 | module "datadog_monitors" {
48 | source = "../../modules/monitors"
49 |
50 | datadog_monitors = module.monitor_configs.map_configs
51 | alert_tags = var.alert_tags
52 | alert_tags_separator = var.alert_tags_separator
53 | restricted_roles_map = local.monitors_roles_map
54 |
55 | context = module.this.context
56 | }
57 |
--------------------------------------------------------------------------------
/examples/rbac/outputs.tf:
--------------------------------------------------------------------------------
1 | output "datadog_monitor_names" {
2 | value = module.datadog_monitors.datadog_monitor_names
3 | description = "Names of the created Datadog monitors"
4 | }
5 |
6 | output "datadog_monitors" {
7 | value = module.datadog_monitors.datadog_monitors
8 | description = "The created Datadog monitors"
9 | }
10 |
11 | output "datadog_available_permissions" {
12 | value = local.available_permissions
13 | description = "Map of available permission names to permission IDs"
14 | }
15 |
--------------------------------------------------------------------------------
/examples/rbac/providers.tf:
--------------------------------------------------------------------------------
1 | # For the example, we use ENV variables `DD_API_KEY` and `DD_APP_KEY` in place of the `api_key` and `app_key` parameters to the provider
2 | # https://registry.terraform.io/providers/DataDog/datadog/latest/docs#argument-reference
3 | provider "datadog" {
4 | }
5 |
--------------------------------------------------------------------------------
/examples/rbac/variables.tf:
--------------------------------------------------------------------------------
1 | variable "alert_tags" {
2 | type = list(string)
3 | description = "List of alert tags to add to all alert messages, e.g. `[\"@opsgenie\"]` or `[\"@devops\", \"@opsgenie\"]`"
4 | }
5 |
6 | variable "alert_tags_separator" {
7 | type = string
8 | description = "Separator for the alert tags. All strings from the `alert_tags` variable will be joined into one string using the separator and then added to the alert message"
9 | }
10 |
11 | variable "monitor_paths" {
12 | type = list(string)
13 | description = "List of paths to Datadog monitor configurations"
14 | }
15 |
16 | variable "role_paths" {
17 | type = list(string)
18 | description = "List of paths to Datadog role configurations"
19 | }
20 |
--------------------------------------------------------------------------------
/examples/rbac/versions.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_version = ">= 1.0.0"
3 |
4 | required_providers {
5 | datadog = {
6 | source = "datadog/datadog"
7 | version = ">= 3.0.0"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/examples/slo/catalog/metric_slo.yaml:
--------------------------------------------------------------------------------
1 | metric-slo:
2 | name: "(SLO) Synthetic Checks"
3 | type: metric
4 | query:
5 | numerator: sum:synthetics.test_runs{status:success}.as_count()
6 | denominator: sum:synthetics.test_runs{*}.as_count()
7 | description: |
8 | Number of Successful Synthetic Checks.
9 | message: |
10 | ({stage} {region}) {instance_id} failed a SLO check
11 | force_delete: true
12 | validate: true
13 | thresholds:
14 | - target: "99.5"
15 | timeframe: "7d"
16 | warning: "99.9"
17 | - target: "99"
18 | timeframe: "30d"
19 | warning: "99.5"
20 | tags:
21 | ManagedBy: terraform
22 | test: true
23 | api_version: null
24 |
--------------------------------------------------------------------------------
/examples/slo/catalog/monitor_slo.yaml:
--------------------------------------------------------------------------------
1 | monitor-slo:
2 | name: "(SLO) EC2 Availability"
3 | type: monitor
4 | description: |
5 | Number of EC2 failed status checks.
6 | message: |
7 | ({stage} {region}) {instance_id} failed a SLO check
8 | force_delete: true
9 | validate: true
10 | thresholds:
11 | - target: "99.5"
12 | timeframe: "7d"
13 | warning: "99.9"
14 | - target: "99"
15 | timeframe: "30d"
16 | warning: "99.5"
17 | # Either `monitor_ids` or `monitors` should be provided
18 | # `monitor_ids` is a list of externally created monitors to use for this monitor-based SLO
19 | # If `monitors` map is provided, the monitors will be created by the module and assigned to the SLO
20 | monitor_ids: null
21 | monitors:
22 | ec2-failed-status-check:
23 | name: "(EC2) Status Check"
24 | type: metric alert
25 | query: |
26 | avg(last_10m):avg:aws.ec2.status_check_failed{*} by {instance_id} > 0
27 | message: |
28 | ({stage} {region}) {instance_id} failed a status check
29 | escalation_message: ""
30 | tags:
31 | ManagedBy: Terraform
32 | priority: 3
33 | notify_no_data: false
34 | notify_audit: true
35 | require_full_window: true
36 | enable_logs_sample: false
37 | force_delete: true
38 | include_tags: true
39 | locked: false
40 | renotify_interval: 60
41 | timeout_h: 0
42 | evaluation_delay: 60
43 | new_host_delay: 300
44 | new_group_delay: 0
45 | groupby_simple_monitor: false
46 | renotify_occurrences: 0
47 | renotify_statuses: []
48 | validate: true
49 | no_data_timeframe: 10
50 | threshold_windows: {}
51 | thresholds:
52 | critical: 0
53 | tags:
54 | ManagedBy: terraform
55 | test: true
56 | api_version: null
57 |
--------------------------------------------------------------------------------
/examples/slo/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/slo/fixtures.us-east-2.tfvars:
--------------------------------------------------------------------------------
1 | namespace = "eg"
2 |
3 | stage = "test"
4 |
5 | name = "datadog-slo"
6 |
7 | slo_paths = ["catalog/*.yaml"]
8 |
--------------------------------------------------------------------------------
/examples/slo/main.tf:
--------------------------------------------------------------------------------
1 | locals {
2 | slo_files = flatten([for p in var.slo_paths : fileset(path.module, p)])
3 | slo_list = [for f in local.slo_files : yamldecode(file(f))]
4 | slo_map = merge(local.slo_list...)
5 | }
6 |
7 | module "datadog_slo" {
8 | source = "../../modules/slo"
9 |
10 | datadog_slos = local.slo_map
11 |
12 | alert_tags = var.alert_tags
13 | alert_tags_separator = var.alert_tags_separator
14 |
15 | context = module.this.context
16 | }
17 |
--------------------------------------------------------------------------------
/examples/slo/outputs.tf:
--------------------------------------------------------------------------------
1 | output "datadog_monitor_slos" {
2 | value = module.datadog_slo.datadog_monitor_slos
3 | description = "Map of created monitor-based SLOs"
4 | }
5 |
6 | output "datadog_monitor_slo_monitors" {
7 | value = module.datadog_slo.datadog_monitor_slo_monitors
8 | description = "Created monitors for the monitor-based SLOs"
9 | }
10 |
11 | output "datadog_metric_slos" {
12 | value = module.datadog_slo.datadog_metric_slos
13 | description = "Map of created metric-based SLOs"
14 | }
15 |
16 | output "datadog_metric_slo_alerts" {
17 | value = module.datadog_slo.datadog_metric_slo_alerts
18 | description = "Map of created metric-based SLO alerts"
19 | }
20 |
--------------------------------------------------------------------------------
/examples/slo/providers.tf:
--------------------------------------------------------------------------------
1 | # For the example, we use ENV variables `DD_API_KEY` and `DD_APP_KEY` in place of the `api_key` and `app_key` parameters to the provider
2 | # https://registry.terraform.io/providers/DataDog/datadog/latest/docs#argument-reference
3 | provider "datadog" {
4 | validate = false
5 | }
6 |
7 |
--------------------------------------------------------------------------------
/examples/slo/variables.tf:
--------------------------------------------------------------------------------
1 | variable "slo_paths" {
2 | type = list(string)
3 | description = "List of paths to Datadog SLO configurations"
4 | }
5 |
6 | variable "alert_tags" {
7 | type = list(string)
8 | description = "List of alert tags to add to all alert messages, e.g. `[\"@opsgenie\"]` or `[\"@devops\", \"@opsgenie\"]`"
9 | default = null
10 | }
11 |
12 | variable "alert_tags_separator" {
13 | type = string
14 | description = "Separator for the alert tags. All strings from the `alert_tags` variable will be joined into one string using the separator and then added to the alert message"
15 | default = "\n"
16 | }
17 |
--------------------------------------------------------------------------------
/examples/slo/versions.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_version = ">= 1.0.0"
3 |
4 | required_providers {
5 | datadog = {
6 | source = "datadog/datadog"
7 | version = ">= 3.0.0"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/examples/synthetics/catalog/api-schema/api-multistep-test.yaml:
--------------------------------------------------------------------------------
1 | "Multistep API test":
2 | name: Multistep API test
3 | status: paused
4 | type: api
5 | tags: []
6 | config:
7 | configVariables: []
8 | steps:
9 | - id: 47q-xx9-2ng
10 | name: Top Level echo server
11 | subtype: http
12 | extractedValues:
13 | - type: http_body
14 | parser:
15 | type: json_path
16 | value: $.headers.host
17 | name: SERVER_HOST
18 | secure: false
19 | allowFailure: true
20 | isCritical: true
21 | retry:
22 | count: 1
23 | interval: 3000
24 | assertions:
25 | - operator: lessThan
26 | type: responseTime
27 | target: 1000
28 | - operator: is
29 | type: statusCode
30 | target: 200
31 | - operator: is
32 | property: content-type
33 | type: header
34 | target: application/json
35 | - type: body
36 | operator: validatesJSONPath
37 | target:
38 | jsonPath: $.headers.cookie
39 | operator: contains
40 | targetValue: DatadogTest=yes
41 | request:
42 | method: GET
43 | url: https://echo.free.beeceptor.com
44 | headers:
45 | cookie: DatadogTest=yes
46 | httpVersion: any
47 | - id: e5i-w66-4ed
48 | name: No file list
49 | subtype: http
50 | extractedValues: []
51 | allowFailure: false
52 | isCritical: true
53 | retry:
54 | count: 0
55 | interval: 300
56 | assertions:
57 | - operator: lessThan
58 | type: responseTime
59 | target: 1000
60 | - operator: is
61 | type: statusCode
62 | target: 200
63 | - operator: is
64 | property: content-type
65 | type: header
66 | target: application/json
67 | - type: body
68 | operator: doesNotContain
69 | target: tmp
70 | request:
71 | method: GET
72 | url: https://echo.free.beeceptor.com/?echo_file=/
73 | httpVersion: any
74 | message: ""
75 | options:
76 | tick_every: 86400
77 | min_failure_duration: 0
78 | min_location_failed: 1
79 | retry:
80 | count: 0
81 | interval: 300
82 | monitor_options:
83 | renotify_interval: 0
84 | locations:
85 | - aws:us-west-2
86 | subtype: multi
87 |
--------------------------------------------------------------------------------
/examples/synthetics/catalog/api-schema/browser-multistep-test.yaml:
--------------------------------------------------------------------------------
1 | # Example multistep browser test using API schema
2 |
3 | "Example multistep test":
4 | name: Example multistep test
5 | status: paused
6 | type: browser
7 | config:
8 | assertions: []
9 | configVariables: []
10 | request:
11 | method: GET
12 | headers: {}
13 | url: https://archive.sweetops.com/
14 | setCookie: ""
15 | variables:
16 | - example: Oct
17 | name: DELAYED_MONTH
18 | pattern: '{{ date(-3d, MMM) }}'
19 | secure: false
20 | type: text
21 | - example: Oct
22 | name: THIS_MONTH
23 | pattern: '{{ date(0d, MMM) }}'
24 | secure: false
25 | type: text
26 | message: |-
27 | Slack Archive outdated
28 | options:
29 | device_ids:
30 | - edge.laptop_large
31 | - chrome.mobile_small
32 | ignoreServerCertificateError: false
33 | disableCors: false
34 | disableCsp: false
35 | noScreenshot: false
36 | tick_every: 43200
37 | min_location_failed: 1
38 | retry:
39 | count: 0
40 | interval: 300
41 | monitor_options:
42 | renotify_interval: 0
43 | rumSettings:
44 | isEnabled: false
45 | enableProfiling: false
46 | enableSecurityTesting: false
47 | locations:
48 | - aws:us-west-2
49 | steps:
50 | - name: Click on button "leadinModal-close"
51 | params:
52 | element:
53 | multiLocator:
54 | ab: /*[local-name()="html"][1]/*[local-name()="body"][1]/*[local-name()="div"][7]/*[local-name()="div"][2]/*[local-name()="button"][1]
55 | at: /descendant::*[@role="dialog"]/descendant::*[@*[local-name()="aria-label"]="Close"]
56 | cl: /descendant::*[contains(concat(' ', normalize-space(@class), ' '), " leadinModal-close ")]
57 | clt: /descendant::*[contains(concat(' ', normalize-space(@class), ' '), " leadinModal-close ")]
58 | co: '[{"tagName":"BUTTON","text":"close","textType":"aria-label"}]'
59 | ro: //*[contains(concat(' ', normalize-space(@class), ' '), " leadinModal-close ")]
60 | targetOuterHTML:
61 | url: https://archive.sweetops.com/
62 | timeout: 11
63 | type: click
64 | allowFailure: true
65 | isCritical: false
66 | noScreenshot: true
67 | - name: Click on i "menu"
68 | params:
69 | element:
70 | multiLocator:
71 | ab: /*[local-name()="html"][1]/*[local-name()="body"][1]/*[local-name()="header"][1]/*[local-name()="nav"][1]/*[local-name()="div"][1]/*[local-name()="a"][2]/*[local-name()="i"][1]
72 | at: /descendant::*[@role="banner"]/descendant::*[@href="#"]/*[local-name()="i"][1]
73 | cl: /descendant::*[contains(concat(' ', normalize-space(@class), ' '), " sidenav-trigger ")]/descendant::*[contains(concat(' ', normalize-space(@class), ' '), " material-icons ")]
74 | clt: /descendant::*[contains(concat(' ', normalize-space(@class), ' '), " sidenav-trigger ")]/descendant::*[contains(concat(' ', normalize-space(@class), ' '), " material-icons ")]
75 | co: '[{"text":"menu","textType":"directText"}]'
76 | ro: //*[text()[normalize-space(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞŸŽŠŒ', 'abcdefghijklmnopqrstuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿžšœ')) = "menu"]]
77 | targetOuterHTML: menu
78 | url: https://archive.sweetops.com/
79 | type: click
80 | allowFailure: false
81 | isCritical: true
82 | noScreenshot: false
83 | - name: Click on link "#terraform"
84 | params:
85 | element:
86 | multiLocator:
87 | ab: /*[local-name()="html"][1]/*[local-name()="body"][1]/*[local-name()="ul"][1]/*[local-name()="li"][19]/*[local-name()="a"][1]
88 | at: ""
89 | cl: /descendant::*[contains(concat(' ', normalize-space(@class), ' '), " sidenav ")]/*[local-name()="li"][19]/descendant::*[contains(concat(' ', normalize-space(@class), ' '), " page-link ")]
90 | clt: /descendant::*[contains(concat(' ', normalize-space(@class), ' '), " sidenav ")]/*[local-name()="li"][19]/descendant::*[contains(concat(' ', normalize-space(@class), ' '), " page-link ")]
91 | co: '[{"text":"#terraform","textType":"directText"},{"relation":"AFTER","tagName":"LI","text":" #refarch ","textType":"innerText"}]'
92 | ro: //*[@href="/terraform/"]
93 | targetOuterHTML: #terraform
94 | url: https://archive.sweetops.com/
95 | timeout: 0
96 | type: click
97 | allowFailure: false
98 | isCritical: true
99 | noScreenshot: false
100 | - name: Test link "current month" content
101 | params:
102 | check: matchRegex
103 | element:
104 | multiLocator:
105 | ab: /*[local-name()="html"][1]/*[local-name()="body"][1]/*[local-name()="main"][1]/*[local-name()="div"][1]/*[local-name()="div"][1]/*[local-name()="div"][1]/*[local-name()="div"][2]/*[local-name()="div"][1]/*[local-name()="ul"][2]/*[local-name()="li"][10]/*[local-name()="a"][1]
106 | at: ""
107 | cl: /descendant::*[contains(concat(' ', normalize-space(@class), ' '), " post ")]/descendant::*[contains(concat(' ', normalize-space(@class), ' '), " curr-month ")][1]/*[local-name()="a"][1]
108 | clt: /descendant::*[contains(concat(' ', normalize-space(@class), ' '), " post ")]/descendant::*[contains(concat(' ', normalize-space(@class), ' '), " curr-month ")][1]/descendant::*[text()[normalize-space(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞŸŽŠŒ', 'abcdefghijklmnopqrstuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿžšœ')) = "oct"]]
109 | co: '[{"text":"oct","textType":"directText"},{"relation":"BEFORE","tagName":"DIV","text":" #terraform (2023-10) discussions related to terraform or terraform modules","textType":"innerText"}]'
110 | ro: //*[local-name()="div"][1]/*[local-name()="ul"][2]/*[10]/*
111 | targetOuterHTML: Oct
112 | url: https://archive.sweetops.com/terraform/2023/10/
113 | userLocator:
114 | failTestOnCannotLocate: true
115 | values:
116 | - type: css
117 | value: div.pagination-wrapper:has(+ header) li.curr-month > a
118 | value: '{{ DELAYED_MONTH }}|{{ THIS_MONTH }}'
119 | timeout: 5
120 | type: assertElementContent
121 | allowFailure: false
122 | isCritical: true
123 | noScreenshot: false
124 |
--------------------------------------------------------------------------------
/examples/synthetics/catalog/terraform-schema/http.yaml:
--------------------------------------------------------------------------------
1 | simple:
2 | name: "cloudposse.com website test"
3 | message: "Cloud Posse website is not reachable"
4 | type: api
5 | subtype: http
6 | tags:
7 | ManagedBy: Terraform
8 | locations:
9 | - "all"
10 | status: "paused"
11 | request_definition:
12 | url: "https://cloudposse.com"
13 | method: GET
14 | request_headers: {}
15 | request_query: {}
16 | set_cookie: ""
17 | options_list:
18 | tick_every: 1800
19 | assertion:
20 | - type: statusCode
21 | operator: is
22 | target: "200"
23 |
24 | complex:
25 | name: "cloudposse.com complex test"
26 | message: "Cloud Posse website is not reachable (advanced test)"
27 | type: api
28 | subtype: http
29 | tags:
30 | ManagedBy: Terraform
31 | locations:
32 | - "aws:us-west-2"
33 | status: "paused"
34 | request_definition:
35 | url: "https://cloudposse.com"
36 | method: GET
37 | request_headers:
38 | Accept-Charset: "utf-8, iso-8859-1;q=0.5"
39 | Accept: "text/html"
40 | request_query:
41 | hello: world
42 | set_cookie: ""
43 | options_list:
44 | tick_every: 1800
45 | follow_redirects: true
46 | retry:
47 | count: 3
48 | interval: 5
49 | monitor_options:
50 | renotify_interval: 1440
51 | assertion:
52 | - type: statusCode
53 | operator: is
54 | target: "200"
55 | - type: body
56 | operator: validatesJSONPath
57 | targetjsonpath:
58 | operator: is
59 | targetvalue: true
60 | jsonpath: status
61 |
--------------------------------------------------------------------------------
/examples/synthetics/catalog/terraform-schema/ssl.yaml:
--------------------------------------------------------------------------------
1 | ssl-test:
2 | name: "SSL Test"
3 | message: "The certificate has expired!"
4 | type: api
5 | subtype: ssl
6 | tags:
7 | ManagedBy: Terraform
8 | locations:
9 | - "aws:us-west-2"
10 | status: "paused"
11 | request_definition:
12 | host: cloudposse.com
13 | port: 443
14 | request_headers: {}
15 | request_query: {}
16 | set_cookie: ""
17 | options_list:
18 | tick_every: 1800
19 | assertion:
20 | - type: certificate
21 | operator: isInMoreThan
22 | target: 30
23 |
--------------------------------------------------------------------------------
/examples/synthetics/fixtures.us-east-2.tfvars:
--------------------------------------------------------------------------------
1 | namespace = "eg"
2 |
3 | stage = "test"
4 |
5 | name = "datadog-synthetics"
6 |
7 | alert_tags = ["@opsgenie"]
8 |
9 | alert_tags_separator = "\n"
10 |
11 | synthetic_paths = ["catalog/terraform-schema/*.yaml", "catalog/api-schema/*.yaml"]
12 |
--------------------------------------------------------------------------------
/examples/synthetics/main.tf:
--------------------------------------------------------------------------------
1 | locals {
2 | synthetics_files = flatten([for p in var.synthetic_paths : fileset(path.module, p)])
3 | synthetics_list = [for f in local.synthetics_files : yamldecode(file(f))]
4 | synthetics_map = merge(local.synthetics_list...)
5 | }
6 |
7 | module "datadog_synthetics" {
8 | source = "../../modules/synthetics"
9 |
10 | datadog_synthetics = local.synthetics_map
11 | alert_tags = var.alert_tags
12 | alert_tags_separator = var.alert_tags_separator
13 |
14 | locations = ["aws:us-east-2"]
15 | context = module.this.context
16 | }
17 |
--------------------------------------------------------------------------------
/examples/synthetics/outputs.tf:
--------------------------------------------------------------------------------
1 | output "datadog_synthetics_test_names" {
2 | value = module.datadog_synthetics.datadog_synthetics_test_names
3 | description = "Names of the created Datadog synthetic tests"
4 | }
5 |
6 | output "datadog_synthetics_test_ids" {
7 | value = module.datadog_synthetics.datadog_synthetics_test_ids
8 | description = "IDs of the created Datadog synthetic tests"
9 | }
10 |
11 | output "datadog_synthetics_test_monitor_ids" {
12 | value = module.datadog_synthetics.datadog_synthetics_test_monitor_ids
13 | description = "IDs of the monitors associated with the Datadog synthetics tests"
14 | }
15 |
16 | output "datadog_synthetic_tests" {
17 | value = module.datadog_synthetics.datadog_synthetic_tests
18 | description = "Synthetic tests created in DataDog"
19 | sensitive = true
20 | }
21 |
--------------------------------------------------------------------------------
/examples/synthetics/providers.tf:
--------------------------------------------------------------------------------
1 | # For the example, we use ENV variables `DD_API_KEY` and `DD_APP_KEY` in place of the `api_key` and `app_key` parameters to the provider
2 | # https://registry.terraform.io/providers/DataDog/datadog/latest/docs#argument-reference
3 | provider "datadog" {
4 | validate = false
5 | }
6 |
--------------------------------------------------------------------------------
/examples/synthetics/variables.tf:
--------------------------------------------------------------------------------
1 | variable "alert_tags" {
2 | type = list(string)
3 | description = "List of alert tags to add to all alert messages, e.g. `[\"@opsgenie\"]` or `[\"@devops\", \"@opsgenie\"]`"
4 | }
5 |
6 | variable "alert_tags_separator" {
7 | type = string
8 | description = "Separator for the alert tags. All strings from the `alert_tags` variable will be joined into one string using the separator and then added to the alert message"
9 | }
10 |
11 | variable "synthetic_paths" {
12 | type = list(string)
13 | description = "List of paths to Datadog synthetic test configurations to be deployed"
14 | }
15 |
--------------------------------------------------------------------------------
/examples/synthetics/versions.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_version = ">= 1.0.0"
3 |
4 | required_providers {
5 | datadog = {
6 | source = "datadog/datadog"
7 | version = ">=3.43.1"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/main.tf:
--------------------------------------------------------------------------------
1 | locals {
2 | enabled = module.this.enabled
3 | alert_tags = local.enabled && var.alert_tags != null ? format("%s%s", var.alert_tags_separator, join(var.alert_tags_separator, var.alert_tags)) : ""
4 | }
5 |
6 | # https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor
7 | resource "datadog_monitor" "default" {
8 | for_each = local.enabled ? var.datadog_monitors : {}
9 |
10 | name = each.value.name
11 | type = each.value.type
12 | query = each.value.query
13 | message = format("%s%s", each.value.message, local.alert_tags)
14 | escalation_message = lookup(each.value, "escalation_message", null)
15 | require_full_window = lookup(each.value, "require_full_window", null)
16 | notify_no_data = lookup(each.value, "notify_no_data", null)
17 | new_host_delay = lookup(each.value, "new_host_delay", null)
18 | evaluation_delay = lookup(each.value, "evaluation_delay", null)
19 | no_data_timeframe = lookup(each.value, "no_data_timeframe", null)
20 | renotify_interval = lookup(each.value, "renotify_interval", null)
21 | notify_audit = lookup(each.value, "notify_audit", null)
22 | timeout_h = lookup(each.value, "timeout_h", null)
23 | include_tags = lookup(each.value, "include_tags", null)
24 | enable_logs_sample = lookup(each.value, "enable_logs_sample", null)
25 | force_delete = lookup(each.value, "force_delete", null)
26 |
27 | monitor_thresholds {
28 | warning = lookup(each.value.thresholds, "warning", null)
29 | warning_recovery = lookup(each.value.thresholds, "warning_recovery", null)
30 | critical = lookup(each.value.thresholds, "critical", null)
31 | critical_recovery = lookup(each.value.thresholds, "critical_recovery", null)
32 | ok = lookup(each.value.thresholds, "ok", null)
33 | unknown = lookup(each.value.thresholds, "unknown", null)
34 | }
35 |
36 | monitor_threshold_windows {
37 | recovery_window = lookup(each.value.threshold_windows, "recovery_window", null)
38 | trigger_window = lookup(each.value.threshold_windows, "trigger_window", null)
39 | }
40 |
41 | # Assign restricted roles
42 | # Only these roles will have access to the monitor according to their permissions
43 | restricted_roles = try(var.restricted_roles_map[each.key], null)
44 |
45 | # `restricted_roles` conflicts with `locked`
46 | # Use `locked`` only if `restricted_roles` is not provided
47 | locked = try(var.restricted_roles_map[each.key], null) == null ? lookup(each.value, "locked", null) : null
48 |
49 | tags = lookup(each.value, "tags", module.this.tags)
50 | }
51 |
--------------------------------------------------------------------------------
/modules/child_organization/main.tf:
--------------------------------------------------------------------------------
1 | # https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/child_organization
2 | # https://github.com/hashicorp/cdktf-provider-datadog/blob/main/API.md
3 |
4 | locals {
5 | enabled = module.this.enabled
6 | }
7 |
8 | resource "datadog_child_organization" "default" {
9 | count = local.enabled ? 1 : 0
10 | name = var.organization_name
11 | }
12 |
--------------------------------------------------------------------------------
/modules/child_organization/outputs.tf:
--------------------------------------------------------------------------------
1 | output "id" {
2 | value = try(datadog_child_organization.default[0].id, "")
3 | description = "Organization ID"
4 | }
5 |
6 | output "description" {
7 | value = try(datadog_child_organization.default[0].description, "")
8 | description = "Description of the organization"
9 | }
10 |
11 | output "public_id" {
12 | value = try(datadog_child_organization.default[0].public_id, "")
13 | description = "Public ID of the organization"
14 | }
15 |
16 | output "user" {
17 | value = try(datadog_child_organization.default[0].user[0], {})
18 | description = "Information about organization users"
19 | }
20 |
21 | output "settings" {
22 | value = try(datadog_child_organization.default[0].settings[0], {})
23 | description = "Organization settings"
24 | }
25 |
26 | output "api_key" {
27 | value = try(datadog_child_organization.default[0].api_key[0], {})
28 | description = "Information about Datadog API key"
29 | sensitive = true
30 | }
31 |
32 | output "application_key" {
33 | value = try(datadog_child_organization.default[0].application_key[0], {})
34 | description = "Datadog application key with its associated metadata"
35 | sensitive = true
36 | }
37 |
--------------------------------------------------------------------------------
/modules/child_organization/variables.tf:
--------------------------------------------------------------------------------
1 | variable "organization_name" {
2 | type = string
3 | description = "Datadog organization name"
4 | }
5 |
--------------------------------------------------------------------------------
/modules/child_organization/versions.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_version = ">= 1.0.0"
3 |
4 | required_providers {
5 | datadog = {
6 | source = "datadog/datadog"
7 | version = ">= 3.0.0"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/modules/monitors/README.md:
--------------------------------------------------------------------------------
1 | ## monitors
2 |
3 | This module creates Datadog [monitors](https://docs.datadoghq.com/api/latest/monitors/).
4 | It accepts all the configuration parameters supported by the Datadog Terraform
5 | resource.
6 |
7 | ## Usage
8 |
9 | The `datadog_monitors` input takes a map of test definitions. You must supply
10 | the keys for the map, but the values can follow either of two schemas described
11 | below.
12 |
13 | There are some optional additions to the monitor definition that are not
14 | part of the Datadog API schema. These are:
15 | - `force_delete` (boolean): If true, when deleting the monitor, the monitor
16 | will be deleted even if it is referenced by other resources.
17 | - `validate` (boolean): If false, the monitor will not be validated during
18 | the Terraform plan phase.
19 | - `enabled` (boolean): If false, the monitor will not be created. This is to
20 | allow you to suppress a monitor created through merging configuration snippets.
21 |
22 | ### Tags
23 |
24 | This module provides special handling for tags. The `tags` attribute of a monitor
25 | definition in the Datadog API and the Terraform resource is a list of strings.
26 | However, the Cloud Posse (as well as AWS) default is to use a map of strings
27 | for tags. This module allows you to provide either a list or a map for the tags.
28 |
29 | If you provide a list, it will be used as is. If you provide a map, it will be
30 | converted to a list of strings in the format `key:value` (or `key` if `value` is
31 | `null`). If you provide no tag settings at all, not even an empty list or map,
32 | the module will use the default tags from the [null-label](https://github.com/cloudposse/terraform-null-label/) module.
33 |
34 | ### API Schema (preferred)
35 |
36 | Datadog provides a REST API for managing monitors. We refer to the responses
37 | to the API requests for monitor definitions (`GET https://api.datadoghq.com/api/v1/monitor/{monitor_id}`)
38 | as the "API Schema" for the tests. This should correspond to the documented
39 | API "Model" for Monitors plus additional information such as creation date,
40 | but if the documentation and the API response differ, we use the API response
41 | as the source of truth.
42 |
43 | You can retrieve Monitor definitions from Datadog via the Datadog Web Console.
44 | Navigate to the monitor you want to retrieve, click the gear icon in the upper
45 | right (representing "settings"), and select "Export". This will display a JSON
46 | representation of the monitor definition. You can then click the "Copy" button
47 | to copy the JSON to the clipboard.
48 |
49 | Example of JSON for monitors
50 |
51 | Note that many elements of the monitor definition are optional, and the JSON
52 | representation will only include the elements that are set. This is an example
53 | of a monitor, not a comprehensive list of all possible elements.
54 |
55 | ```json
56 | {
57 | "name": "schedule-test",
58 | "type": "event-v2 alert",
59 | "query": "events(\"service:datadog-agent\").rollup(\"cardinality\", \"@evt.id\").current(\"1h\") > 2345",
60 | "message": "No message",
61 | "tags": [
62 | "test:examplemonitor",
63 | "Terratest"
64 | ],
65 | "options": {
66 | "thresholds": {
67 | "critical": 2345,
68 | "warning": 987
69 | },
70 | "enable_logs_sample": false,
71 | "notify_audit": false,
72 | "on_missing_data": "default",
73 | "include_tags": false,
74 | "scheduling_options": {
75 | "custom_schedule": {
76 | "recurrences": [
77 | {
78 | "rrule": "FREQ=DAILY;INTERVAL=1;BYHOUR=17;BYMINUTE=54",
79 | "timezone": "America/Los_Angeles"
80 | }
81 | ]
82 | },
83 | "evaluation_window": {
84 | "hour_starts": 7
85 | }
86 | }
87 | },
88 | "priority": 5
89 | }
90 | ```
91 |
92 |
93 |
94 | You can find other examples in the [examples/complete/monitors-test/](../../examples/complete/monitors-test) directory.
95 |
96 | You can then use the `jsondecode()` function in Terraform to convert the JSON
97 | to a Terraform object, and use that object as the value for the monitor definition.
98 | You can also transform the JSON to HCL other ways, however you prefer. The
99 | relevant point is that this module will accept the monitor definition in this
100 | schema. Any field in the API schema that does not have a counterpart in the
101 | Terraform schema will be ignored.
102 |
103 | #### Special Notes
104 |
105 | The `alert_tags` input is provided for convenience. It is used to add notification
106 | tags to the monitor message. However, it does not check to see if the tags are
107 | already present. If the tags are already present, they will still be added again.
108 |
109 | > [!IMPORTANT]
110 | >
111 | > If you define a monitor via JSON, and then you use `alert_tags` when creating
112 | > it, and then export the JSON representation of the created monitor definition,
113 | > it will not match because of the added tags.
114 |
115 | Note that `restricted_roles_map` provides a convenient way to specify the
116 | `restricted_roles` attribute of the monitor. This is a map of monitors to
117 | sets of Datadog unique role identifiers. If provided, this will override the
118 | `restricted_roles` attribute of the monitor definition. If not provided, the
119 | `restricted_roles` attribute of the monitor definition will be used, if present.
120 |
121 | > [!IMPORTANT]
122 | >
123 | > ### Legacy schema (deprecated)
124 | >
125 | > Historically, and preserved for backward compatibility, you can configure tests
126 | > using the schema used in v1.3.0 and earlier. This schema flattens the monitor
127 | > definition, pulling up the `options` attributes to the top level.
128 | >
129 | > Note that not all fields are supported in this schema, and it is only preserved for
130 | > backward compatibility. We recommend that you use the API schema going forward.
131 |
132 |
--------------------------------------------------------------------------------
/modules/monitors/main.tf:
--------------------------------------------------------------------------------
1 | locals {
2 | enabled = module.this.enabled
3 |
4 | alert_tags = local.enabled && var.alert_tags != null ? format("%s%s", var.alert_tags_separator, join(var.alert_tags_separator, var.alert_tags)) : ""
5 | }
6 |
7 | # https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor
8 | resource "datadog_monitor" "default" {
9 | for_each = { for k, v in local.datadog_monitors : k => v if local.enabled && lookup(v, "enabled", true) }
10 |
11 | name = each.value.name
12 | type = each.value.type
13 | query = each.value.query
14 | message = format("%s%s", each.value.message, local.alert_tags)
15 | priority = try(each.value.priority, null)
16 |
17 | # Assign restricted roles
18 | # Only these roles will have access to the monitor according to their permissions.
19 | # If `restricted_roles` is present var map, it takes precedence over the setting in the monitor definition.
20 | restricted_roles = try(var.restricted_roles_map[each.key], try(each.value.restricted_roles, null))
21 |
22 | # `restricted_roles` conflicts with `locked`, which is deprecated.
23 | # Use `locked`` only if present and `restricted_roles` is not provided.
24 | locked = try(var.restricted_roles_map[each.key], try(each.value.restricted_roles, null)) == null ? try(each.value.options.locked, null) : null
25 |
26 | # Setting tags is complicated and moved to the bottom of this resource.
27 |
28 | ##### Attributes under `options` in the API model ####
29 | enable_logs_sample = try(each.value.options.enable_logs_sample, null)
30 | # enable_samples is read-only in provider v3.36.0
31 | # enable_samples = try(each.value.options.enable_samples, null)
32 | escalation_message = try(each.value.options.escalation_message, null)
33 | evaluation_delay = try(each.value.options.evaluation_delay, null)
34 | group_retention_duration = try(each.value.options.group_retention_duration, null)
35 | groupby_simple_monitor = try(each.value.options.groupby_simple_monitor, null)
36 | include_tags = try(each.value.options.include_tags, null)
37 | # min_failure_duration is not supported in provider v3.36.0
38 | # min_failure_duration = try(each.value.options.min_failure_duration, null)
39 | # min_location_failed is not supported in provider v3.36.0
40 | # min_location_failed = try(each.value.options.min_location_failed, null)
41 | new_group_delay = try(each.value.options.new_group_delay, null)
42 | no_data_timeframe = try(each.value.options.no_data_timeframe, null)
43 | notification_preset_name = try(each.value.options.notification_preset_name, null)
44 | notify_audit = try(each.value.options.notify_audit, null)
45 | notify_by = try(each.value.options.notify_by, null)
46 | notify_no_data = try(each.value.options.notify_no_data, null)
47 | on_missing_data = try(each.value.options.on_missing_data, null)
48 | renotify_interval = try(each.value.options.renotify_interval, null)
49 | renotify_occurrences = try(each.value.options.renotify_occurrences, null)
50 | renotify_statuses = try(each.value.options.renotify_statuses, null)
51 | require_full_window = try(each.value.options.require_full_window, null)
52 | timeout_h = try(each.value.options.timeout_h, null)
53 |
54 | # DEPRECATED: `new_host_delay` is deprecated, but still needed when set to zero to override default.
55 | # So it is ignored unless set to zero.
56 | new_host_delay = try(each.value.options.new_host_delay, null) == 0 ? 0 : null
57 |
58 | dynamic "monitor_thresholds" {
59 | for_each = try([each.value.options.thresholds], [])
60 | iterator = thresholds
61 | content {
62 | critical = lookup(thresholds.value, "critical", null)
63 | critical_recovery = lookup(thresholds.value, "critical_recovery", null)
64 | ok = lookup(thresholds.value, "ok", null)
65 | unknown = lookup(thresholds.value, "unknown", null)
66 | warning = lookup(thresholds.value, "warning", null)
67 | warning_recovery = lookup(thresholds.value, "warning_recovery", null)
68 | }
69 | }
70 |
71 | dynamic "monitor_threshold_windows" {
72 | for_each = try([each.value.options.threshold_windows], [])
73 | iterator = threshold_windows
74 | content {
75 | recovery_window = lookup(threshold_windows.value, "recovery_window", null)
76 | trigger_window = lookup(threshold_windows.value, "trigger_window", null)
77 | }
78 | }
79 |
80 | dynamic "scheduling_options" {
81 | # Legacy support. In the API, `scheduling_options` is a map of objects, but legacy it was a list of objects.
82 | for_each = try(tolist(each.value.options.scheduling_options), try([each.value.options.scheduling_options], []))
83 | content {
84 | dynamic "custom_schedule" {
85 | for_each = try([scheduling_options.value.custom_schedule], [])
86 | content {
87 | dynamic "recurrence" {
88 | for_each = try(custom_schedule.value.recurrences, [])
89 | content {
90 | rrule = recurrence.value.rrule
91 | timezone = recurrence.value.timezone
92 | start = try(recurrence.value.start, null)
93 | }
94 | } # recurrence
95 | }
96 | } # custom_schedule
97 |
98 | dynamic "evaluation_window" {
99 | # Legacy support. In the API, `evaluation_window` is a map of objects, but legacy it was a list of objects.
100 | for_each = try(tolist(scheduling_options.value.evaluation_window), try([scheduling_options.value.evaluation_window], []))
101 | content {
102 | day_starts = lookup(evaluation_window.value, "day_starts", null)
103 | hour_starts = lookup(evaluation_window.value, "hour_starts", null)
104 | month_starts = lookup(evaluation_window.value, "month_starts", null)
105 | }
106 | } # evaluation_window
107 | }
108 | } # scheduling_options
109 |
110 | dynamic "variables" {
111 | # There is only one `variables` block in the Terraform model.
112 | for_each = try(length(tolist(each.value.options.variables)), 0) > 0 ? ["variables"] : []
113 | content {
114 | # The JSON `variables` attribute is a list of objects,
115 | # but in Terraform the list is expressed as repeated `event_query` blocks under `variables`.
116 | dynamic "event_query" {
117 | for_each = each.value.options.variables
118 | iterator = query
119 | content {
120 | compute {
121 | aggregation = query.value.compute.aggregation
122 | interval = lookup(query.value.compute, "interval", null)
123 | metric = lookup(query.value.compute, "metric", null)
124 | }
125 |
126 | data_source = query.value.data_source
127 |
128 | dynamic "group_by" {
129 | for_each = try(query.value.group_by, [])
130 | content {
131 | facet = group_by.value.facet
132 | limit = try(group_by.value.limit, null)
133 |
134 | dynamic "sort" {
135 | for_each = try([group_by.value.sort], [])
136 | content {
137 | aggregation = sort.value.aggregation
138 | metric = try(sort.value.metric, null)
139 | order = try(sort.value.order, null)
140 | }
141 | } # sort
142 | }
143 | } # group_by
144 |
145 | indexes = try(query.value.indexes, null)
146 | name = query.value.name
147 |
148 | search {
149 | # Cannot be null or empty string, use "*" which is equivalent to "" and matches everything
150 | # See https://github.com/DataDog/terraform-provider-datadog/pull/2275
151 | query = coalesce(try(query.value.search.query, null), "*")
152 | }
153 | }
154 | } # event_query
155 | }
156 | } # variables
157 |
158 | ### End of `options` attributes ###
159 |
160 | # `force_delete` and `validate` are not part of the Datadog API monitor model.
161 | # They are features provided by the Datadog Terraform provider to help manage the monitors.
162 | force_delete = lookup(each.value, "force_delete", null)
163 | # If validate is set to false, Terraform will skip the validation call done during plan.
164 | validate = lookup(each.value, "validate", null)
165 |
166 | ############################
167 | # TAGS
168 | ############################
169 | # Datadog's tags are a list of strings, but Terraform's tags are a map of strings.
170 | # Convert Terraform tags map to Datadog tags list
171 | # If a key is supplied with a value:
172 | # tags:
173 | # key: value
174 | # it will render the tag as "key:value"
175 | # If a key is supplied without a value (null)
176 | # tags:
177 | # key: null
178 | # it will render the tag as simply "key"
179 | # However, the API schema takes a list of tags
180 | # tags:
181 | # - key:value
182 | # so if the tags are provided as a list, we just pass that through.
183 | # If the monitor has no setting for tags, we add the default tags, if enabled.
184 | tags = try(tolist(each.value.tags), null) != null ? try(tolist(each.value.tags), null) : [
185 | # If the user has supplied a map of tags, use it. Otherwise, use the default tags if enabled.
186 | for tagk, tagv in try(tomap(each.value.tags), var.default_tags_enabled ? module.this.tags : {}) : (tagv != null ? format("%s:%s", tagk, tagv) : tagk)
187 | ]
188 | }
189 |
--------------------------------------------------------------------------------
/modules/monitors/normalize-legacy.tf:
--------------------------------------------------------------------------------
1 | # Legacy support
2 | #
3 | # The preferred way to use this module is to supply configuration matching the
4 | # model of the Datadog API. However, the module also supports a legacy mode
5 | # where the configuration that is in the model under `options` can be provided
6 | # at the top level of the map. This mode is deprecated and will not be enhanced
7 | # to include new features, e.g. `group_retention_duration` or
8 | # `scheduling_options.custom_schedule`.
9 | #
10 |
11 | locals {
12 | # Step one, list all the keys that are in the legacy configuration
13 | # that should be under options. Only the keys that were in the legacy
14 | # module are listed here. New keys should not be added to this list.
15 | # Instead, users should convert their configuration to the new model.
16 | legacy_attributes = [
17 | "enable_logs_sample",
18 | "escalation_message",
19 | "evaluation_delay",
20 | "groupby_simple_monitor",
21 | "include_tags",
22 | "locked",
23 | "new_group_delay",
24 | "new_host_delay",
25 | "no_data_timeframe",
26 | "notify_audit",
27 | "notify_no_data",
28 | "priority",
29 | "renotify_interval",
30 | "renotify_occurrences",
31 | "renotify_statuses",
32 | "require_full_window",
33 | "scheduling_options",
34 | "thresholds",
35 | "threshold_windows",
36 | "timeout_h",
37 | "validate"
38 | ]
39 |
40 | # Step two, create a map containing the legacy options that should be moved.
41 | # We do not need to remove the keys from the original map, as they will simply be ignored.
42 | legacy_option_attributes_maps = { for k, v in var.datadog_monitors : k => { for attr in local.legacy_attributes : attr => v[attr] if try(v[attr], null) != null } }
43 |
44 | # Step three, add the legacy options to the maps under the `options` key,
45 | # but only if the `options` key is not already present.
46 | datadog_monitors = { for k, v in var.datadog_monitors : k => merge(
47 | { options = local.legacy_option_attributes_maps[k] }, v)
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/modules/monitors/outputs.tf:
--------------------------------------------------------------------------------
1 | output "datadog_monitor_names" {
2 | value = values(datadog_monitor.default)[*].name
3 | description = "Names of the created Datadog monitors"
4 | }
5 |
6 | output "datadog_monitor_ids" {
7 | value = values(datadog_monitor.default)[*].id
8 | description = "IDs of the created Datadog monitors"
9 | }
10 |
11 | output "datadog_monitors" {
12 | value = datadog_monitor.default
13 | description = "Datadog monitor outputs"
14 | }
15 |
--------------------------------------------------------------------------------
/modules/monitors/variables.tf:
--------------------------------------------------------------------------------
1 | # https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor
2 | variable "datadog_monitors" {
3 | # We use `any` type here because the `datadog_monitors` map can have multiple configurations
4 | # and it is too complex to model all possible configurations in the type system.
5 | type = any
6 | description = <<-EOT
7 | Map of Datadog monitor configurations. See the README for details on the expected structure.
8 | Keys will be used as monitor names if not provided in the `name` attribute.
9 | Attributes match [Datadog "Create a monitor" API](https://docs.datadoghq.com/api/v1/monitors/#create-a-monitor).
10 | For backward compatibility, attributes under `options` in the API schema that were
11 | previously allowed at the top level remain available at the top level if no `options` are provided.
12 | Because `new_host_delay` is deprecated, it is ignored unless set to zero.
13 | EOT
14 | }
15 |
16 | variable "alert_tags" {
17 | type = list(string)
18 | description = "List of alert tags to add to all alert messages, e.g. `[\"@opsgenie\"]` or `[\"@devops\", \"@opsgenie\"]`"
19 | default = null
20 | }
21 |
22 | variable "alert_tags_separator" {
23 | type = string
24 | description = "Separator for the alert tags. All strings from the `alert_tags` variable will be joined into one string using the separator and then added to the alert message"
25 | default = "\n"
26 | }
27 |
28 | variable "restricted_roles_map" {
29 | type = map(set(string))
30 | description = <<-EOT
31 | Map of `datadog_monitors` map keys to sets of Datadog unique role IDs
32 | to restrict access to each monitor. If provided, it will override
33 | the `restricted_roles` attribute in the monitor definition.
34 | EOT
35 | default = {}
36 | }
37 |
38 | variable "default_tags_enabled" {
39 | type = bool
40 | description = <<-EOT
41 | If true, monitors without `tags` in their definitions will have tags
42 | from `null-label` added to them. Note that even an empty `list` or `map` of tags in
43 | the monitor definition will keep the default tags from being added.
44 | EOT
45 | default = true
46 | }
47 |
--------------------------------------------------------------------------------
/modules/monitors/versions.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_version = ">= 1.0.0"
3 |
4 | required_providers {
5 | datadog = {
6 | source = "datadog/datadog"
7 | # >= 3.36.0 is required, so that bugfix for "start" is included.
8 | # See https://github.com/DataDog/terraform-provider-datadog/issues/2255
9 | version = ">= 3.36.0"
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/modules/organization_settings/main.tf:
--------------------------------------------------------------------------------
1 | # https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/child_organization
2 | # https://github.com/hashicorp/cdktf-provider-datadog/blob/main/API.md
3 |
4 | locals {
5 | enabled = module.this.enabled
6 | }
7 |
8 | resource "datadog_organization_settings" "default" {
9 | count = local.enabled ? 1 : 0
10 |
11 | name = var.organization_name
12 |
13 | settings {
14 | saml {
15 | # Free and Trial organizations cannot enable SAML
16 | enabled = var.saml_enabled
17 | }
18 |
19 | saml_autocreate_users_domains {
20 | domains = var.saml_autocreate_users_domains
21 | enabled = var.saml_autocreate_users_enabled
22 | }
23 |
24 | saml_strict_mode {
25 | enabled = var.saml_strict_mode_enabled
26 | }
27 |
28 | saml_idp_initiated_login {
29 | enabled = var.saml_idp_initiated_login_enabled
30 | }
31 |
32 | private_widget_share = var.private_widget_share
33 |
34 | saml_autocreate_access_role = var.saml_autocreate_access_role
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/modules/organization_settings/outputs.tf:
--------------------------------------------------------------------------------
1 | output "id" {
2 | value = try(datadog_organization_settings.default[0].id, "")
3 | description = "Organization settings ID"
4 | }
5 |
6 | output "description" {
7 | value = try(datadog_organization_settings.default[0].description, "")
8 | description = "Description of the organization"
9 | }
10 |
11 | output "public_id" {
12 | value = try(datadog_organization_settings.default[0].public_id, "")
13 | description = "Public ID of the organization"
14 | }
15 |
16 | output "settings" {
17 | value = try(datadog_organization_settings.default[0].settings, {})
18 | description = "Organization settings"
19 | }
20 |
--------------------------------------------------------------------------------
/modules/organization_settings/variables.tf:
--------------------------------------------------------------------------------
1 | # https://docs.datadoghq.com/account_management/org_settings/#overview
2 |
3 | variable "organization_name" {
4 | type = string
5 | description = "Datadog organization name"
6 | }
7 |
8 | variable "saml_enabled" {
9 | type = bool
10 | default = false
11 | description = "Whether or not SAML is enabled for the child organization. Note that Free and Trial organizations cannot enable SAML"
12 | }
13 |
14 | variable "saml_autocreate_users_domains" {
15 | type = list(string)
16 | default = []
17 | description = "List of domains where the SAML automated user creation is enabled"
18 | }
19 |
20 | variable "saml_autocreate_users_enabled" {
21 | type = bool
22 | default = false
23 | description = "Whether or not the automated user creation based on SAML domain is enabled"
24 | }
25 |
26 | variable "saml_idp_initiated_login_enabled" {
27 | type = bool
28 | default = true
29 | description = "Whether or not IdP initiated login is enabled for the Datadog organization"
30 | }
31 |
32 | variable "saml_strict_mode_enabled" {
33 | type = bool
34 | default = false
35 | description = "Whether or not the SAML strict mode is enabled. If true, all users must log in with SAML"
36 | }
37 |
38 | variable "private_widget_share" {
39 | type = bool
40 | default = false
41 | description = "Whether or not the organization users can share widgets outside of Datadog"
42 | }
43 |
44 | variable "saml_autocreate_access_role" {
45 | type = string
46 | default = "ro"
47 | description = "The access role of an autocreated user. Options are `st` (standard user), `adm` (admin user), or `ro` (read-only user). Allowed enum values: `st`, `adm` , `ro`, `ERROR`"
48 | }
49 |
--------------------------------------------------------------------------------
/modules/organization_settings/versions.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_version = ">= 1.0.0"
3 |
4 | required_providers {
5 | datadog = {
6 | source = "datadog/datadog"
7 | version = ">= 3.0.0"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/modules/permissions/datadog-permissions.md:
--------------------------------------------------------------------------------
1 | # Datadog Permissions
2 |
3 | ## Available Permissions
4 |
5 | ```hcl
6 | permissions = {
7 | "admin" = "984a2bd4-d3b4-11e8-a1ff-a7f660d43029"
8 | "api_keys_read" = "372896c4-f923-11ea-adbc-4fecd107156d"
9 | "api_keys_write" = "3e4d4d28-f923-11ea-adbc-e3565938c12e"
10 | "apm_apdex_manage_write" = "53950c54-2dce-11eb-84c0-a79ae108f6f8"
11 | "apm_primary_operation_write" = "61765026-2dce-11eb-84c0-833e230d1b8f"
12 | "apm_retention_filter_read" = "43fa188e-2dce-11eb-84c0-835ad1fd6287"
13 | "apm_retention_filter_write" = "465cfe66-2dce-11eb-84c0-6baa888239fa"
14 | "apm_service_ingest_read" = "4916eebe-2dce-11eb-84c0-271cb2c672e8"
15 | "apm_service_ingest_write" = "4e3f02b4-2dce-11eb-84c0-2fca946a6efc"
16 | "apm_tag_management_write" = "5cbe5f9c-2dce-11eb-84c0-872d3e9f1076"
17 | "billing_edit" = "46a301e0-ec5c-11ea-aa9f-6ba6cc675d8c"
18 | "billing_read" = "46a301df-ec5c-11ea-aa9f-970a9ae645e5"
19 | "dashboards_public_share" = "d90f6832-d3d8-11e9-a77a-bf8a2607f864"
20 | "dashboards_write" = "d90f6831-d3d8-11e9-a77a-4fd230ddbc6a"
21 | "data_scanner_read" = "bf0dcf7c-90af-11eb-9b82-da7ad0900002"
22 | "data_scanner_write" = "bf0dcf7d-90af-11eb-9b82-da7ad0900002"
23 | "incident_settings_read" = "12efc20f-d36c-11eb-a9b8-da7ad0900002"
24 | "incident_settings_write" = "12efc210-d36c-11eb-a9b8-da7ad0900002"
25 | "incident_write" = "12efc211-d36c-11eb-a9b8-da7ad0900002"
26 | "integrations_api" = "fcac2ad8-2843-11eb-8315-0fe47949d625"
27 | "logs_generate_metrics" = "979df720-aed7-11e9-99c6-a7eb8373165a"
28 | "logs_live_tail" = "6f66600e-dd12-11e8-9e55-7f30fbb45e73"
29 | "logs_modify_indexes" = "62cc036c-dd12-11e8-9e54-db9995643092"
30 | "logs_public_config_api" = "1a92ede2-6cb2-11e9-99c6-2b3a4a0cdf0a"
31 | "logs_read_archives" = "b382b982-8535-11ea-93de-2bf1bdf20798"
32 | "logs_read_data" = "1af86ce4-7823-11ea-93dc-d7cad1b1c6cb"
33 | "logs_read_index_data" = "5e605652-dd12-11e8-9e53-375565b8970e"
34 | "logs_write_archives" = "87b00304-dd12-11e8-9e59-cbeb5f71f72f"
35 | "logs_write_exclusion_filters" = "7d7c98ac-dd12-11e8-9e56-93700598622d"
36 | "logs_write_facets" = "6ba32d22-0e1a-11eb-ba44-bf9a5aafaa39"
37 | "logs_write_historical_view" = "07c3c146-f7f8-11ea-acf6-0bd62b9ae60e"
38 | "logs_write_pipelines" = "811ac4ca-dd12-11e8-9e57-676a7f0beef9"
39 | "logs_write_processors" = "84aa3ae4-dd12-11e8-9e58-a373a514ccd0"
40 | "metric_tags_write" = "46a301e4-ec5c-11ea-aa9f-87282b3a50cc"
41 | "monitors_downtime" = "4d87d5f8-d8b1-11e9-a77a-eb9c8350d04f"
42 | "monitors_write" = "48ef71ea-d8b1-11e9-a77a-93f408470ad0"
43 | "org_app_keys_read" = "46a301db-ec5c-11ea-aa9f-2fe72193d60e"
44 | "org_app_keys_write" = "46a301dc-ec5c-11ea-aa9f-13b33f8f46ea"
45 | "rum_apps_write" = "8106300a-54f7-11eb-8cbc-7781a434a67b"
46 | "security_monitoring_filters_read" = "98b984f4-b16d-11eb-a2c6-da7ad0900002"
47 | "security_monitoring_filters_write" = "98b984f5-b16d-11eb-a2c6-da7ad0900002"
48 | "security_monitoring_rules_read" = "7314eb20-aa58-11ea-95e2-6fb6e4a451d5"
49 | "security_monitoring_rules_write" = "7b516476-aa58-11ea-95e2-93718cd56369"
50 | "security_monitoring_signals_read" = "80de1ec0-aa58-11ea-95e2-aff381626d5d"
51 | "standard" = "984d2f00-d3b4-11e8-a200-bb47109e9987"
52 | "synthetics_default_settings_read" = "5c6b88e2-f923-11ea-adbc-abf57d079420"
53 | "synthetics_default_settings_write" = "642eebe6-f923-11ea-adbc-eb617674ea04"
54 | "synthetics_global_variable_read" = "4628ca54-f923-11ea-adbc-4b2b7f88c5e9"
55 | "synthetics_global_variable_write" = "4ada6e36-f923-11ea-adbc-0788e5c5e3cf"
56 | "synthetics_private_location_read" = "46a301dd-ec5c-11ea-aa9f-97edfb345bc9"
57 | "synthetics_private_location_write" = "46a301de-ec5c-11ea-aa9f-a73252c24806"
58 | "synthetics_read" = "5025ee24-f923-11ea-adbc-576ea241df8d"
59 | "synthetics_write" = "55f4b5ec-f923-11ea-adbc-1bfa2334a755"
60 | "usage_edit" = "46a301e2-ec5c-11ea-aa9f-1f511b7305fd"
61 | "usage_read" = "46a301e1-ec5c-11ea-aa9f-afa39f6f3e36"
62 | "user_access_invite" = "9ac1d8cc-e707-11ea-aa2d-73d37e989a9d"
63 | "user_access_manage" = "9de604d8-e707-11ea-aa2d-93f1a783b3a3"
64 | "user_app_keys" = "46a301da-ec5c-11ea-aa9f-73bedeab67ee"
65 | }
66 | ```
67 |
--------------------------------------------------------------------------------
/modules/permissions/main.tf:
--------------------------------------------------------------------------------
1 | # https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/role
2 | # https://registry.terraform.io/providers/DataDog/datadog/latest/docs/data-sources/permissions
3 | # https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor
4 | # https://docs.datadoghq.com/api/latest/monitors/#create-a-monitor
5 | # https://docs.datadoghq.com/account_management/rbac/?tab=datadogapplication
6 | # https://docs.datadoghq.com/account_management/rbac/permissions/
7 | # https://docs.datadoghq.com/api/latest/monitors/
8 | # https://github.com/hashicorp/cdktf-provider-datadog/blob/main/API.md
9 |
10 | # Get all available Datadog permissions
11 | data "datadog_permissions" "available_permissions" {
12 | count = local.enabled ? 1 : 0
13 | }
14 |
15 | locals {
16 | enabled = module.this.enabled
17 | permissions = local.enabled ? data.datadog_permissions.available_permissions[0].permissions : null
18 | }
19 |
--------------------------------------------------------------------------------
/modules/permissions/outputs.tf:
--------------------------------------------------------------------------------
1 | output "permissions" {
2 | value = local.permissions
3 | description = "Available Datadog permissions. It's a map of permission names to permissions IDs"
4 | }
5 |
--------------------------------------------------------------------------------
/modules/permissions/versions.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_version = ">= 1.0.0"
3 |
4 | required_providers {
5 | datadog = {
6 | source = "datadog/datadog"
7 | version = ">= 3.0.0"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/modules/roles/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 |
--------------------------------------------------------------------------------
/modules/roles/main.tf:
--------------------------------------------------------------------------------
1 | locals {
2 | enabled = module.this.enabled
3 | permissions = module.permissions.permissions
4 | }
5 |
6 | module "permissions" {
7 | source = "../permissions"
8 | context = module.this.context
9 | }
10 |
11 | resource "datadog_role" "default" {
12 | for_each = local.enabled ? var.datadog_roles : {}
13 |
14 | name = each.value.name
15 |
16 | dynamic "permission" {
17 | for_each = each.value.permissions
18 | content {
19 | id = local.permissions != null ? lookup(local.permissions, permission.value, null) : null
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/modules/roles/outputs.tf:
--------------------------------------------------------------------------------
1 | output "datadog_role_names" {
2 | value = values(datadog_role.default)[*].name
3 | description = "Names of the created Datadog roles"
4 | }
5 |
6 | output "datadog_role_ids" {
7 | value = values(datadog_role.default)[*].id
8 | description = "IDs of the created Datadog roles"
9 | }
10 |
11 | output "datadog_roles" {
12 | value = datadog_role.default
13 | description = "Created Datadog roles"
14 | }
15 |
--------------------------------------------------------------------------------
/modules/roles/variables.tf:
--------------------------------------------------------------------------------
1 | # https://docs.datadoghq.com/account_management/rbac/?tab=datadogapplication
2 | variable "datadog_roles" {
3 | type = map(object({
4 | name = string
5 | permissions = set(string)
6 | }))
7 | description = "Map of Datadog role configurations. See catalog for examples"
8 | }
9 |
--------------------------------------------------------------------------------
/modules/roles/versions.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_version = ">= 1.0.0"
3 |
4 | required_providers {
5 | datadog = {
6 | source = "datadog/datadog"
7 | version = ">= 3.0.0"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/modules/slo/README.md:
--------------------------------------------------------------------------------
1 | # Datadog SLO
2 |
3 | This module is responsible for creating Datadog [Service Level Objectives](https://docs.datadoghq.com/monitors/service_level_objectives/) and their related monitors and alerts.
4 |
5 | The module can create metric-based SLOs (and the corresponding alerts) and monitor-based SLOs (and the corresponding monitors).
6 |
7 | ## Alerts
8 |
9 | Datadog alerts for SLOs are terraformed through the monitor object.
10 |
11 | An SLO can have many thresholds set, but a monitor can only have one. In order to get around this, the module creates Datadog monitors for each threshold within an SLO.
12 |
13 | ## Usage
14 |
15 | Example of metric-based SLO:
16 |
17 | ```yaml
18 | metric-slo:
19 | name: "(SLO) Synthetic Checks"
20 | type: metric
21 | query:
22 | numerator: sum:synthetics.test_runs{status:success}.as_count()
23 | denominator: sum:synthetics.test_runs{*}.as_count()
24 | description: |
25 | Number of Successful Synthetic Checks.
26 | message: |
27 | ({stage} {region}) {instance_id} failed a SLO check
28 | force_delete: true
29 | validate: true
30 | thresholds:
31 | - target: "99.5"
32 | timeframe: "7d"
33 | warning: "99.9"
34 | - target: "99"
35 | timeframe: "30d"
36 | warning: "99.5"
37 | tags:
38 | ManagedBy: terraform
39 | test: true
40 | api_version: null
41 | ```
42 |
43 | Example of monitor-based SLO:
44 |
45 | ```yaml
46 | monitor-slo:
47 | name: "(SLO) EC2 Availability"
48 | type: monitor
49 | description: |
50 | Number of EC2 failed status checks.
51 | message: |
52 | ({stage} {region}) {instance_id} failed a SLO check
53 | force_delete: true
54 | validate: true
55 | thresholds:
56 | - target: "99.5"
57 | timeframe: "7d"
58 | warning: "99.9"
59 | - target: "99"
60 | timeframe: "30d"
61 | warning: "99.5"
62 | # Either `monitor_ids` or `monitors` should be provided
63 | # `monitor_ids` is a list of externally created monitors to use for this monitor-based SLO
64 | # If `monitors` map is provided, the monitors will be created by the module and assigned to the SLO
65 | monitor_ids: null
66 | monitors:
67 | ec2-failed-status-check:
68 | name: "(EC2) Status Check"
69 | type: metric alert
70 | query: |
71 | avg(last_10m):avg:aws.ec2.status_check_failed{*} by {instance_id} > 0
72 | message: |
73 | ({stage} {region}) {instance_id} failed a status check
74 | escalation_message: ""
75 | tags:
76 | ManagedBy: Terraform
77 | priority: 3
78 | notify_no_data: false
79 | notify_audit: true
80 | require_full_window: true
81 | enable_logs_sample: false
82 | force_delete: true
83 | include_tags: true
84 | locked: false
85 | renotify_interval: 60
86 | timeout_h: 0
87 | evaluation_delay: 60
88 | new_host_delay: 300
89 | new_group_delay: 0
90 | groupby_simple_monitor: false
91 | renotify_occurrences: 0
92 | renotify_statuses: []
93 | validate: true
94 | no_data_timeframe: 10
95 | threshold_windows: {}
96 | thresholds:
97 | critical: 0
98 | tags:
99 | ManagedBy: terraform
100 | test: true
101 | api_version: null
102 | ```
103 |
104 | ## References
105 | - [Service Level Objectives](https://docs.datadoghq.com/monitors/service_level_objectives/)
106 | - [Monitor-based SLOs](https://docs.datadoghq.com/monitors/service_level_objectives/monitor/)
107 | - [Datadog Error Budget](https://docs.datadoghq.com/monitors/service_level_objectives/error_budget/)
108 | - [Monitor-based SLO example](https://github.com/DataDog/terraform-provider-datadog/issues/667)
109 |
--------------------------------------------------------------------------------
/modules/slo/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 |
--------------------------------------------------------------------------------
/modules/slo/main.tf:
--------------------------------------------------------------------------------
1 | locals {
2 | enabled = module.this.enabled
3 |
4 | alert_tags = local.enabled && var.alert_tags != null ? format("%s%s", var.alert_tags_separator, join(var.alert_tags_separator, var.alert_tags)) : ""
5 | }
6 |
--------------------------------------------------------------------------------
/modules/slo/metric_slo.tf:
--------------------------------------------------------------------------------
1 | locals {
2 | datadog_metric_slos = { for slo in var.datadog_slos : slo.name => slo if slo.type == "metric" && lookup(slo, "enabled", true) && local.enabled }
3 |
4 | temp_datadog_metric_slo_alerts = flatten([
5 | for name, slo in var.datadog_slos : [
6 | for i, threshold in slo.thresholds : {
7 | slo = slo,
8 | slo_name = format("%s_threshold%s", name, i)
9 | threshold = threshold
10 | }
11 | if slo.type == "metric" && local.enabled && lookup(slo, "enabled", true)
12 | ]
13 | ])
14 |
15 | datadog_metric_slo_alerts = { for monitor in local.temp_datadog_metric_slo_alerts : monitor.slo_name => monitor }
16 | }
17 |
18 | resource "datadog_service_level_objective" "metric_slo" {
19 | for_each = local.datadog_metric_slos
20 |
21 | # Required
22 | name = each.value.name
23 | type = each.value.type
24 |
25 | # Optional
26 | description = lookup(each.value, "description", null)
27 | force_delete = lookup(each.value, "force_delete", true)
28 | validate = lookup(each.value, "validate", false)
29 |
30 | query {
31 | denominator = each.value.query.denominator
32 | numerator = each.value.query.numerator
33 | }
34 |
35 | dynamic "thresholds" {
36 | for_each = each.value.thresholds
37 | content {
38 | target = lookup(thresholds.value, "target", null)
39 | timeframe = lookup(thresholds.value, "timeframe", null)
40 | warning = lookup(thresholds.value, "warning", null)
41 | }
42 | }
43 |
44 | # Convert terraform tags map to Datadog tags map
45 | # If a key is supplied with a value, it will render "key:value" as a tag
46 | # tags:
47 | # key: value
48 | # If a key is supplied without a value (null), it will render "key" as a tag
49 | # tags:
50 | # key: null
51 | tags = [
52 | for tagk, tagv in lookup(each.value, "tags", module.this.tags) : (tagv != null ? format("%s:%s", tagk, tagv) : tagk)
53 | ]
54 | }
55 |
56 | # https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor
57 | resource "datadog_monitor" "metric_slo_alert" {
58 | for_each = local.datadog_metric_slo_alerts
59 |
60 | type = "slo alert"
61 | name = format("(SLO Error Budget Alert) %s", each.value.slo.name)
62 | message = format("%s %s", each.value.slo.message, local.alert_tags)
63 |
64 | query = < ${lookup(each.value.threshold, "target", "99.00")}
66 | EOF
67 |
68 | monitor_thresholds {
69 | critical = lookup(each.value.threshold, "target", null)
70 | }
71 |
72 | # Convert terraform tags map to Datadog tags map
73 | # If a key is supplied with a value, it will render "key:value" as a tag
74 | # tags:
75 | # key: value
76 | # If a key is supplied without a value (null), it will render "key" as a tag
77 | # tags:
78 | # key: null
79 | tags = [
80 | for tagk, tagv in lookup(each.value.slo, "tags", module.this.tags) : (tagv != null ? format("%s:%s", tagk, tagv) : tagk)
81 | ]
82 | }
83 |
--------------------------------------------------------------------------------
/modules/slo/monitor_slo.tf:
--------------------------------------------------------------------------------
1 | locals {
2 | datadog_monitor_slos = { for slo in var.datadog_slos : slo.name => slo if slo.type == "monitor" && lookup(slo, "enabled", true) && local.enabled }
3 | }
4 |
5 | module "datadog_monitors" {
6 | source = "../monitors"
7 |
8 | for_each = local.datadog_monitor_slos
9 |
10 | datadog_monitors = lookup(each.value, "monitors", {})
11 | alert_tags = var.alert_tags
12 | alert_tags_separator = var.alert_tags_separator
13 |
14 | context = module.this.context
15 | }
16 |
17 | resource "datadog_service_level_objective" "monitor_slo" {
18 | for_each = local.datadog_monitor_slos
19 |
20 | # Required
21 | name = each.value.name
22 | type = each.value.type
23 |
24 | dynamic "thresholds" {
25 | for_each = each.value.thresholds
26 | content {
27 | target = lookup(thresholds.value, "target", "99.00")
28 | timeframe = lookup(thresholds.value, "timeframe", "7d")
29 | warning = lookup(thresholds.value, "warning", "99.95")
30 | }
31 | }
32 |
33 | groups = lookup(each.value, "groups", [])
34 |
35 | # Either `monitor_ids` or `monitors` should be provided
36 | # If `monitors` map is provided, the monitors are created in the `datadog_monitors` module
37 | monitor_ids = try(each.value.monitor_ids, null) != null ? each.value.monitor_ids : module.datadog_monitors[each.key].datadog_monitor_ids
38 |
39 | # Optional
40 | description = lookup(each.value, "description", null)
41 | force_delete = lookup(each.value, "force_delete", true)
42 | validate = lookup(each.value, "validate", false)
43 |
44 | # Convert terraform tags map to Datadog tags map
45 | # If a key is supplied with a value, it will render "key:value" as a tag
46 | # tags:
47 | # key: value
48 | # If a key is supplied without a value (null), it will render "key" as a tag
49 | # tags:
50 | # key: null
51 | tags = [
52 | for tagk, tagv in lookup(each.value, "tags", module.this.tags) : (tagv != null ? format("%s:%s", tagk, tagv) : tagk)
53 | ]
54 | }
55 |
--------------------------------------------------------------------------------
/modules/slo/outputs.tf:
--------------------------------------------------------------------------------
1 | output "datadog_monitor_slos" {
2 | value = datadog_service_level_objective.monitor_slo
3 | description = "Map of created monitor-based SLOs"
4 | }
5 |
6 | output "datadog_monitor_slo_monitors" {
7 | value = module.datadog_monitors
8 | description = "Created monitors for the monitor-based SLOs"
9 | }
10 |
11 | output "datadog_metric_slos" {
12 | value = datadog_service_level_objective.metric_slo
13 | description = "Map of created metric-based SLOs"
14 | }
15 |
16 | output "datadog_metric_slo_alerts" {
17 | value = datadog_monitor.metric_slo_alert
18 | description = "Map of created metric-based SLO alerts"
19 | }
20 |
--------------------------------------------------------------------------------
/modules/slo/variables.tf:
--------------------------------------------------------------------------------
1 | variable "datadog_slos" {
2 | type = any
3 | description = "Map of Datadog SLO configurations"
4 | }
5 |
6 | variable "alert_tags" {
7 | type = list(string)
8 | description = "List of alert tags to add to all alert messages, e.g. `[\"@opsgenie\"]` or `[\"@devops\", \"@opsgenie\"]`"
9 | default = null
10 | }
11 |
12 | variable "alert_tags_separator" {
13 | type = string
14 | description = "Separator for the alert tags. All strings from the `alert_tags` variable will be joined into one string using the separator and then added to the alert message"
15 | default = "\n"
16 | }
17 |
--------------------------------------------------------------------------------
/modules/slo/versions.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_version = ">= 1.0.0"
3 |
4 | required_providers {
5 | datadog = {
6 | source = "datadog/datadog"
7 | version = ">= 3.0.0"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/modules/synthetics/README.md:
--------------------------------------------------------------------------------
1 | ## synthetics
2 |
3 | This module creates Datadog [synthetic tests](https://docs.datadoghq.com/api/latest/synthetics/).
4 | It accepts all the configuration parameters supported by the Datadog Terraform
5 | resource except `BasicAuth` authentication wherever it occurs.
6 |
7 | ## Usage
8 |
9 | The `datadog_synthetics` input takes a map of test definitions. You must supply
10 | the keys for the map, but the values can follow either of two schemas described
11 | below.
12 |
13 | ### API Schema
14 |
15 | Datadog provides a REST API for managing synthetic tests. We refer to the responses
16 | to the API requests for test definitions as the "API Schema" for the tests.
17 | (Note that some items in the response are read-only, and are ignored if included
18 | in the definition of a test.) There are errors and omissions in the documentation
19 | of the API output, and where we have found API results that differ from the
20 | documentation, we have used the API results as the source of truth.
21 |
22 | You can retrieve test definitions from the Datadog API in 3 ways:
23 |
24 | 1. You can [retrieve an individual API test](https://docs.datadoghq.com/api/latest/synthetics/#get-an-api-test)
25 | 2. You can [retrieve an individual browser test](https://docs.datadoghq.com/api/latest/synthetics/#get-a-browser-test)
26 | 3. You can [retrieve a list of all tests](https://docs.datadoghq.com/api/latest/synthetics/#get-the-list-of-all-synthetic-tests)
27 |
28 | NOTE: As of this writing (2023-10-20), the list of all tests fails to include the steps in a multistep browser test.
29 | You must use the individual browser test API to retrieve the test definition including the steps.
30 | This is a known issue with Datadog, and hopefully will be fixed soon, but verify that it is fixed before
31 | relying on the list of all tests if you are using multistep browser tests.
32 |
33 | The `datadog_synthetics` input takes a map of test definitions. You must supply
34 | the keys for the map, but the values can simply be the output of
35 | applying Terraform's `jsondecode()` to the output of the API. In the case
36 | of the list of all tests, you must iterate over the list and supply
37 | a key for each test. We recommend that you use the test's `name` as the key.
38 |
39 | For any test, you can optionally add `enabled = false` to disable/delete the test.
40 |
41 | NOTE: Since this module is implemented in Terraform, any field in the API
42 | schema that does not have a counterpart in the Terraform schema will be ignored.
43 | As of this writing (Datadog Terraform provider version 3.30.0), that includes
44 | the `metatdata` field in the steps of a multistep API test.
45 |
46 | See https://github.com/DataDog/terraform-provider-datadog/issues/2155
47 |
48 |
49 | ### Terraform schema
50 |
51 | Historically, and preserved for backward compatibility, you can configure tests
52 | using the `datadog_synthetics` input, which takes an object that is a map of
53 | synthetic tests, each test matching the schema of the `datadog_sythetics_test`
54 | [Terraform resource](https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/synthetics_test). See examples with suffix `-terraform.yaml` in
55 | `examples/synthetics/terraform-schema/catalog`.
56 |
57 | One distinction of this schema is that there is no `config` member. Instead,
58 | elements of `config`, such as `assertions`, are pulled up to the top level
59 | and rendered in the singular, e.g. `assertion`. Another change is that `options` is
60 | renamed `options_list`. When in doubt, refer to the Terraform code to see how
61 | the input is mapped to the Terraform resource.
62 |
63 | Note that the Terraform resource does not support the details of the `element`
64 | field for the steps of a multistep browser test. This module allows you to use an object
65 | following the API schema, or you can use a string that is the JSON encoding
66 | of the object. However, if you use the JSON string encoding, and you are
67 | using a "user locator", you must supply the `element_user_locator` attribute
68 | even though it is already included in the JSON encoding, or else the
69 | Terraform provider will show perpetual drift.
70 |
71 | As with the API schema, you can optionally add `enabled = false` to disable/delete the test.
72 |
73 | #### Unsupported inputs
74 |
75 | Any of the "BasicAuth" inputs are not supported due to their complexity and
76 | rare usage. Usually you can use the `headers` input instead. BasicAuth support
77 | could be added if there is a need.
78 |
79 | ### Locations
80 |
81 | The `locations` input takes a list of locations used to run the test. It
82 | defaults to the special value "all" which is used to indicate all _public_
83 | locations. Any locations included in the `locations` list will be _added_ to the
84 | list of locations specified in the individual test; they will not replace the
85 | list of locations specified in the test.
86 |
--------------------------------------------------------------------------------
/modules/synthetics/outputs.tf:
--------------------------------------------------------------------------------
1 | output "datadog_synthetics_test_names" {
2 | value = values(datadog_synthetics_test.default)[*].name
3 | description = "Names of the created Datadog Synthetic tests"
4 | }
5 |
6 | output "datadog_synthetics_test_ids" {
7 | value = values(datadog_synthetics_test.default)[*].id
8 | description = "IDs of the created Datadog synthetic tests"
9 | }
10 |
11 | output "datadog_synthetics_test_monitor_ids" {
12 | value = values(datadog_synthetics_test.default)[*].monitor_id
13 | description = "IDs of the monitors associated with the Datadog synthetics tests"
14 | }
15 |
16 | output "datadog_synthetic_tests" {
17 | value = datadog_synthetics_test.default
18 | description = "The synthetic tests created in DataDog"
19 | }
20 |
--------------------------------------------------------------------------------
/modules/synthetics/variables.tf:
--------------------------------------------------------------------------------
1 | # https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/synthetics_test
2 | variable "datadog_synthetics" {
3 | type = any
4 | description = "Map of Datadog synthetic test configurations using Terraform or API schema. See README for details."
5 | }
6 |
7 | variable "default_tags_enabled" {
8 | type = bool
9 | description = "If true, all tests will have tags from `null-label` added to them"
10 | default = true
11 | }
12 |
13 | variable "alert_tags" {
14 | type = list(string)
15 | description = "List of alert tags to add to all alert messages, e.g. `[\"@opsgenie\"]` or `[\"@devops\", \"@opsgenie\"]`"
16 | default = []
17 | }
18 |
19 | variable "alert_tags_separator" {
20 | type = string
21 | description = "Separator for the alert tags. All strings from the `alert_tags` variable will be joined into one string using the separator and then added to the alert message"
22 | default = "\n"
23 | }
24 |
25 | variable "locations" {
26 | type = list(string)
27 | description = <<-EOT
28 | Array of locations used to run synthetic tests, or `"all"` to use all public locations.
29 | These locations will be added to any locations specified in the `locations` attribute of a test.
30 | EOT
31 | default = ["all"]
32 | }
33 |
34 |
--------------------------------------------------------------------------------
/modules/synthetics/versions.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_version = ">= 1.0.0"
3 |
4 | required_providers {
5 | datadog = {
6 | source = "datadog/datadog"
7 | # Must have >= 3.43.1 to have fix for https://github.com/DataDog/terraform-provider-datadog/issues/2531
8 | version = ">= 3.43.1"
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/outputs.tf:
--------------------------------------------------------------------------------
1 | output "datadog_monitor_names" {
2 | value = values(datadog_monitor.default)[*].name
3 | description = "Names of the created Datadog monitors"
4 | }
5 |
6 | output "datadog_monitor_ids" {
7 | value = values(datadog_monitor.default)[*].id
8 | description = "IDs of the created Datadog monitors"
9 | }
10 |
11 | output "datadog_monitors" {
12 | value = datadog_monitor.default
13 | description = "Datadog monitor outputs"
14 | }
15 |
--------------------------------------------------------------------------------
/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 examples/complete
34 |
35 | ## Run basic sanity checks against the module itself
36 | module: export TESTS ?= installed lint module-pinning provider-pinning validate terraform-docs input-descriptions output-descriptions
37 | module: deps
38 | $(call RUN_TESTS, ../)
39 |
40 | ## Run tests against example
41 | examples/complete: export TESTS ?= installed lint validate
42 | examples/complete: deps
43 | $(call RUN_TESTS, ../$@)
44 |
--------------------------------------------------------------------------------
/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 TERRAFORM_VERSION ?= $(shell curl -s https://checkpoint-api.hashicorp.com/v1/check/terraform | jq -r -M '.current_version' | cut -d. -f1)
2 |
3 | .DEFAULT_GOAL : all
4 |
5 | .PHONY: all
6 | ## Default target
7 | all: test
8 |
9 | .PHONY : init
10 | ## Initialize tests
11 | init:
12 | @exit 0
13 |
14 | .PHONY : test
15 | ## Run tests
16 | test: init
17 | go mod download
18 | go test -v -timeout 5m -run TestExamplesComplete
19 | go test -v -timeout 5m -run TestExamplesSynthetics
20 | # We can only create Datadog child organizations with terraform, but cannot destroy them
21 | # Warning: Cannot delete organization. Remove organization by contacting support (https://docs.datadoghq.com/help/).
22 | # go test -v -timeout 5m -run TestExamplesChildOrganization
23 |
24 | ## Run tests in docker container
25 | docker/test:
26 | docker run --name terratest --rm -it -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_SESSION_TOKEN -e GITHUB_TOKEN \
27 | -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" \
28 | -v $(CURDIR)/../../:/module/ cloudposse/test-harness:latest -C /module/test/src test
29 |
30 | .PHONY : clean
31 | ## Clean up files
32 | clean:
33 | rm -rf ../../examples/complete/*.tfstate*
34 |
--------------------------------------------------------------------------------
/test/src/examples_child_organization_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | // Test the Terraform module in examples/child_organization using Terratest.
8 | // We can only create Datadog child organizations with terraform, but cannot destroy them
9 | // Warning: Cannot delete organization. Remove organization by contacting support (https://docs.datadoghq.com/help/).
10 | func DisabledTestExamplesChildOrganization(t *testing.T) {
11 | t.Parallel()
12 | /*
13 | randID := strings.ToLower(random.UniqueId())
14 | attributes := []string{randID}
15 |
16 | rootFolder := "../../"
17 | terraformFolderRelativeToRoot := "examples/child_organization"
18 | varFiles := []string{"fixtures.us-east-2.tfvars"}
19 |
20 | tempTestFolder := test_structure.CopyTerraformFolderToTemp(t, rootFolder, terraformFolderRelativeToRoot)
21 |
22 | terraformOptions := &terraform.Options{
23 | // The path to where our Terraform code is located
24 | TerraformDir: tempTestFolder,
25 | Upgrade: true,
26 | // Variables to pass to our Terraform code using -var-file options
27 | VarFiles: varFiles,
28 | Vars: map[string]interface{}{
29 | "attributes": attributes,
30 | },
31 | }
32 |
33 | // At the end of the test, run `terraform destroy` to clean up any resources that were created
34 | defer cleanup(t, terraformOptions, tempTestFolder)
35 |
36 | // This will run `terraform init` and `terraform apply` and fail the test if there are any errors
37 | terraform.InitAndApply(t, terraformOptions)
38 |
39 | // Run `terraform output` to get the value of an output variable
40 | datadogChildOrgId := terraform.OutputList(t, terraformOptions, "id")
41 | // Verify we're getting back the outputs we expect
42 | assert.Greater(t, len(datadogChildOrgId), 0)
43 |
44 | */
45 | }
46 |
--------------------------------------------------------------------------------
/test/src/examples_synthetics_test.go:
--------------------------------------------------------------------------------
1 | package test
2 |
3 | import (
4 | "github.com/gruntwork-io/terratest/modules/logger"
5 | "github.com/gruntwork-io/terratest/modules/random"
6 | "github.com/gruntwork-io/terratest/modules/terraform"
7 | test_structure "github.com/gruntwork-io/terratest/modules/test-structure"
8 | "github.com/stretchr/testify/assert"
9 | "strings"
10 | "testing"
11 | )
12 |
13 | // Test the Terraform module in examples/synthetics using Terratest.
14 | func TestExamplesSynthetics(t *testing.T) {
15 | t.Parallel()
16 | randID := strings.ToLower(random.UniqueId())
17 | attributes := []string{randID}
18 |
19 | rootFolder := "../../"
20 | terraformFolderRelativeToRoot := "examples/synthetics"
21 | varFiles := []string{"fixtures.us-east-2.tfvars"}
22 |
23 | tempTestFolder := test_structure.CopyTerraformFolderToTemp(t, rootFolder, terraformFolderRelativeToRoot)
24 |
25 | terraformOptions := &terraform.Options{
26 | // The path to where our Terraform code is located
27 | TerraformDir: tempTestFolder,
28 | Upgrade: true,
29 | // Variables to pass to our Terraform code using -var-file options
30 | VarFiles: varFiles,
31 | Vars: map[string]interface{}{
32 | "attributes": attributes,
33 | },
34 | }
35 | // Keep the output quiet
36 | if !testing.Verbose() {
37 | terraformOptions.Logger = logger.Discard
38 | }
39 |
40 | // At the end of the test, run `terraform destroy` to clean up any resources that were created
41 | defer cleanup(t, terraformOptions, tempTestFolder)
42 |
43 | // This will run `terraform init` and `terraform apply` and fail the test if there are any errors
44 | terraform.InitAndApply(t, terraformOptions)
45 |
46 | // Run `terraform output` to get the value of an output variable
47 | datadogSyntheticsTestNames := terraform.OutputList(t, terraformOptions, "datadog_synthetics_test_names")
48 | // Verify we're getting back the outputs we expect
49 | assert.Greater(t, len(datadogSyntheticsTestNames), 0)
50 | }
51 |
--------------------------------------------------------------------------------
/test/src/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/cloudposse/terraform-datadog-platform
2 |
3 | go 1.21
4 |
5 | require (
6 | // Known security flaws in terratest dependencies prior to v0.40.15
7 | github.com/gruntwork-io/terratest v0.46.11
8 | github.com/stretchr/testify v1.8.4
9 | )
10 |
11 | require (
12 | cloud.google.com/go v0.110.0 // indirect
13 | cloud.google.com/go/compute v1.19.1 // indirect
14 | cloud.google.com/go/compute/metadata v0.2.3 // indirect
15 | cloud.google.com/go/iam v0.13.0 // indirect
16 | cloud.google.com/go/storage v1.28.1 // indirect
17 | github.com/agext/levenshtein v1.2.3 // indirect
18 | github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
19 | github.com/aws/aws-sdk-go v1.44.122 // indirect
20 | github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
21 | github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
22 | github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
23 | github.com/davecgh/go-spew v1.1.1 // indirect
24 | github.com/emicklei/go-restful/v3 v3.9.0 // indirect
25 | github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0 // indirect
26 | github.com/go-logr/logr v1.2.4 // indirect
27 | github.com/go-openapi/jsonpointer v0.19.6 // indirect
28 | github.com/go-openapi/jsonreference v0.20.2 // indirect
29 | github.com/go-openapi/swag v0.22.3 // indirect
30 | github.com/go-sql-driver/mysql v1.4.1 // indirect
31 | github.com/gogo/protobuf v1.3.2 // indirect
32 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
33 | github.com/golang/protobuf v1.5.3 // indirect
34 | github.com/google/gnostic-models v0.6.8 // indirect
35 | github.com/google/go-cmp v0.5.9 // indirect
36 | github.com/google/gofuzz v1.2.0 // indirect
37 | github.com/google/uuid v1.3.0 // indirect
38 | github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
39 | github.com/googleapis/gax-go/v2 v2.7.1 // indirect
40 | github.com/gruntwork-io/go-commons v0.8.0 // indirect
41 | github.com/hashicorp/errwrap v1.0.0 // indirect
42 | github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
43 | github.com/hashicorp/go-getter v1.7.5 // indirect
44 | github.com/hashicorp/go-multierror v1.1.0 // indirect
45 | github.com/hashicorp/go-safetemp v1.0.0 // indirect
46 | github.com/hashicorp/go-version v1.6.0 // indirect
47 | github.com/hashicorp/hcl/v2 v2.9.1 // indirect
48 | github.com/hashicorp/terraform-json v0.13.0 // indirect
49 | github.com/imdario/mergo v0.3.11 // indirect
50 | github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a // indirect
51 | github.com/jmespath/go-jmespath v0.4.0 // indirect
52 | github.com/josharian/intern v1.0.0 // indirect
53 | github.com/json-iterator/go v1.1.12 // indirect
54 | github.com/klauspost/compress v1.15.11 // indirect
55 | github.com/mailru/easyjson v0.7.7 // indirect
56 | github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326 // indirect
57 | github.com/mitchellh/go-homedir v1.1.0 // indirect
58 | github.com/mitchellh/go-testing-interface v1.14.1 // indirect
59 | github.com/mitchellh/go-wordwrap v1.0.1 // indirect
60 | github.com/moby/spdystream v0.2.0 // indirect
61 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
62 | github.com/modern-go/reflect2 v1.0.2 // indirect
63 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
64 | github.com/pmezard/go-difflib v1.0.0 // indirect
65 | github.com/pquerna/otp v1.2.0 // indirect
66 | github.com/russross/blackfriday/v2 v2.1.0 // indirect
67 | github.com/spf13/pflag v1.0.5 // indirect
68 | github.com/tmccombs/hcl2json v0.3.3 // indirect
69 | github.com/ulikunitz/xz v0.5.11 // indirect
70 | github.com/urfave/cli v1.22.2 // indirect
71 | github.com/zclconf/go-cty v1.9.1 // indirect
72 | go.opencensus.io v0.24.0 // indirect
73 | golang.org/x/crypto v0.21.0 // indirect
74 | golang.org/x/net v0.23.0 // indirect
75 | golang.org/x/oauth2 v0.8.0 // indirect
76 | golang.org/x/sys v0.18.0 // indirect
77 | golang.org/x/term v0.18.0 // indirect
78 | golang.org/x/text v0.14.0 // indirect
79 | golang.org/x/time v0.3.0 // indirect
80 | golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
81 | google.golang.org/api v0.114.0 // indirect
82 | google.golang.org/appengine v1.6.7 // indirect
83 | google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
84 | google.golang.org/grpc v1.56.3 // indirect
85 | google.golang.org/protobuf v1.33.0 // indirect
86 | gopkg.in/inf.v0 v0.9.1 // indirect
87 | gopkg.in/yaml.v2 v2.4.0 // indirect
88 | gopkg.in/yaml.v3 v3.0.1 // indirect
89 | k8s.io/api v0.28.4 // indirect
90 | k8s.io/apimachinery v0.28.4 // indirect
91 | k8s.io/client-go v0.28.4 // indirect
92 | k8s.io/klog/v2 v2.100.1 // indirect
93 | k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect
94 | k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect
95 | sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
96 | sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
97 | sigs.k8s.io/yaml v1.3.0 // indirect
98 | )
99 |
--------------------------------------------------------------------------------
/variables.tf:
--------------------------------------------------------------------------------
1 | # https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor
2 | variable "datadog_monitors" {
3 | type = map(object({
4 | name = string
5 | type = string
6 | message = string
7 | escalation_message = string
8 | query = string
9 | tags = list(string)
10 | notify_no_data = bool
11 | new_host_delay = number
12 | evaluation_delay = number
13 | no_data_timeframe = number
14 | renotify_interval = number
15 | notify_audit = bool
16 | timeout_h = number
17 | enable_logs_sample = bool
18 | include_tags = bool
19 | require_full_window = bool
20 | locked = bool
21 | force_delete = bool
22 | threshold_windows = map(any)
23 | thresholds = map(any)
24 | }))
25 | description = "Map of Datadog monitor configurations. See catalog for examples"
26 | }
27 |
28 | variable "alert_tags" {
29 | type = list(string)
30 | description = "List of alert tags to add to all alert messages, e.g. `[\"@opsgenie\"]` or `[\"@devops\", \"@opsgenie\"]`"
31 | default = null
32 | }
33 |
34 | variable "alert_tags_separator" {
35 | type = string
36 | description = "Separator for the alert tags. All strings from the `alert_tags` variable will be joined into one string using the separator and then added to the alert message"
37 | default = "\n"
38 | }
39 |
40 | variable "restricted_roles_map" {
41 | type = map(set(string))
42 | description = "Map of monitors names to sets of Datadog roles to restrict access to each monitor"
43 | default = {}
44 | }
45 |
--------------------------------------------------------------------------------
/versions.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_version = ">= 1.0.0"
3 |
4 | required_providers {
5 | datadog = {
6 | source = "datadog/datadog"
7 | version = ">= 3.0.0"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------